<?php

namespace App\V3\V3_2_6\Services;

use App\Exceptions\Exceptions;
use App\Services\CommonService;
use App\V3\V3_2_6\Models\LogInStorageModel;
use App\V3\V3_2_6\Models\LogOutStorageModel;
use App\V3\V3_2_6\Models\MaterielProductContentModel;
use App\V3\V3_2_6\Models\MaterielTypeModel;
use App\V3\V3_2_6\Models\ProductFillOrBalanceContentModel;
use App\V3\V3_2_6\Models\ProductFillOrBalanceModel;
use App\V3\V3_2_6\Models\ProductHistoryModel;
use App\V3\V3_2_6\Models\ProductOrderModel;
use App\V3\V3_2_6\Models\ProductSlaveContentModel;
use App\V3\V3_2_6\Models\ProductSlaveContentStorageModel;
use App\V3\V3_2_6\Models\ProductSlaveModel;
use App\V3\V3_2_6\Models\SellGoodsDetail;
use App\V3\V3_2_6\Models\SellModel;
use App\V3\V3_2_6\Models\SerialNumberModel;
use App\V3\V3_2_6\Models\StorageManageModel;
use App\V3\V3_2_6\Models\StorageModel;
use App\V3\V3_2_6\Models\StorageShelfLocationModel;
use App\V3\V3_2_6\Models\StorageShelfModel;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
use Exception;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Facades\Validator;

class ProductService
{
    //生产订单列表
    public static function list(array $data, array $condition, $keyword, $startTime, $endTime)
    {
        if($data['search_type'] != 0) {
            switch($data['search_type']) {
                case 1://商品名
                    $result = self::searchByMaterielName($data, $condition, $keyword, $startTime, $endTime);
                    break;
                case 2://规格名
                    $result = self::searchByTypeName($data, $condition, $keyword, $startTime, $endTime);
                    break;
                case 3://商品编号
                    $result = self::searchByMaterielNo($data, $condition, $keyword, $startTime, $endTime);
                    break;
                case 4://内部单号
                    $result = self::searchByOrderNo($data, $condition, $keyword, $startTime, $endTime);
                    break;
                case 5://关联单号
                    $result = self::searchByRelationNo($data, $condition, $keyword, $startTime, $endTime);
                    break;
                case 6://操作人
                    $result = self::searchByOperator($data, $condition, $keyword, $startTime, $endTime);
                    break;
            }
        }
        else {
            //全部
            $result = self::searchAll($data, $condition, $keyword, $startTime, $endTime);
        }

        return $result;
    }

    //新建
    public static function add(array $data)
    {
        DB::beginTransaction();

        try {
            //product_source:订单来源；0:普通生产订单;1:销售单;
            switch($data['product_source']) {
                case 0:
                    $productOrderId = self::normalAdd($data);
                    break;
                case 1:
                    $productOrderId = self::addFromSell($data);
                    break;
            }

            DB::commit();
            return ['code' => 0, 'msg' => 'success', 'data' => $productOrderId];
        }
        catch (Exception $e) {
            DB::rollBack();
            Log::debug('添加生产订单异常:'.var_export($data, true));
            return ['code' => 1, 'msg' => $e->getMessage(), 'data' => ''];
        }
    }

    //新建普通生产订单
    private static function normalAdd(array $data)
    {
        //参数验证
        $validator = Validator::make($data, [
            'task_content' =>'required|string',//生产任务
            'materiel_content' =>'required|string',//原料信息
        ],
            [
                'task_content.required' => '参数`生产任务`缺失',
                'materiel_content.required' => '参数`原料信息`缺失'
            ]
        );

        //参数错误响应
        if ($info = $validator->errors()->first()) {
            throw new Exception($info);
        }

        $taskContent = json_decode($data['task_content'], true);
        $materielContent = json_decode($data['materiel_content'], true);
        $typeInfo = self::checkTypeInfo($taskContent, $materielContent);//检查生产任务信息

        self::checkContentInfo($materielContent);//检查生产原料信息
//        self::compareTaskAndContent($typeInfo, $materielContent);//检查生产原料是否足够完成生产任务

        $productOrderId = self::addProduct(count($taskContent), $data, $relationNo = '');
        self::addProductSlave($taskContent, $productOrderId, $data);
        self::addProductContent($data, $materielContent, $productOrderId);

        $typeData = [];
        foreach($taskContent as $value) {
            if($value['is_product_materiel']) {
                $contentData = MaterielProductContentModel::where('product_id', $value['type_id'])->get()->toArray();

                foreach($contentData as $val) {
                    if(isset($typeData[$val['type_id']])) {
                        $typeData[$val['type_id']]['num'] += $value['num'] * $val['num'];
                    }
                    else {
                        $typeData[$val['type_id']] = [
                            'type_id' => $val['type_id'],
                            'num' => $value['num'] * $val['num'],
                            'type' => 1
                        ];
                    }
                }
            }
            else {
                if(isset($typeData[$value['type_id']])) {
                    $typeData[$value['type_id']]['num'] += $value['num'];
                }
                else {
                    $typeData[$value['type_id']] = [
                        'type_id' => $value['type_id'],
                        'num' => $value['num']
                    ];
                }
            }
        }

        $arr = [];
        foreach($typeData as $vv) {
            if(!isset($arr[$vv['type_id']])) {
                $arr[$vv['type_id']] = $vv;
            }
            else {
                $arr[$vv['type_id']]['num'] += $vv['num'];
            }
        }

        foreach($arr as $v) {
            ProductSlaveContentModel::where([
                'type_id' => $v['type_id'],
                'product_order_id' => $productOrderId,
            ])
                ->update(['actual_num' => $v['num']]);
        }

        return $productOrderId;
    }

    //销售单一键生产生产订单
    private static function addFromSell(array $data)
    {
        $sellInfo = SellModel::detail($data['product_source_id'])->toArray();

        if(empty($sellInfo)) {
            throw new Exception('无效销售单');
        }

        if($sellInfo['has_product_order']) {
            throw new Exception('销售单无法重复生成生产订单');
        }

        if($sellInfo['out_status'] == 2) {
            throw new Exception('销售单已完成出库，无法生成新的生产订单');
        }

        //通过销售单组建生产任务
        $taskContent = [];
        foreach($sellInfo['materiel_info'] as $value) {
            $typesInfo = MaterielTypeModel::where('id', $value['materiel_type_id'])->first();

            if($value['num'] > $value['out_num']) {
                $taskContent[] = [
                    'type_id' => $value['materiel_type_id'],
                    'is_product_materiel' => $typesInfo['is_product_materiel'],
                    'num' => $value['num'] - $value['out_num']
                ];
            }
        }

        $materielContent = json_decode($data['materiel_content'], true);
        $typeInfo = self::checkTypeInfo($taskContent, $materielContent);//检查生产任务信息

        self::checkContentInfo($materielContent);//检查生产原料信息
//        self::compareTaskAndContent($typeInfo, $materielContent);//检查生产原料是否足够完成生产任务

        $productOrderId = self::addProduct(count($taskContent), $data, $relationNo = '');

        self::addProductSlave($taskContent, $productOrderId, $data);
        self::addProductContent($data, $materielContent, $productOrderId);

        SellModel::where('id', $data['product_source_id'])->update(['has_product_order' => 1]);

        $typeData = [];
        foreach($taskContent as $value) {
            if($value['is_product_materiel']) {
                $contentData = MaterielProductContentModel::where('product_id', $value['type_id'])->get()->toArray();

                foreach($contentData as $val) {
                    if(isset($typeData[$value['type_id']])) {
                        $typeData[$value['type_id']]['num'] += $value['num'] * $val['num'];
                    }
                    else {
                        $typeData[] = [
                            'type_id' => $val['type_id'],
                            'num' => $value['num'] * $val['num'],
                        ];
                    }
                }
            }
            else {
                if(isset($typeData[$value['type_id']])) {
                    $typeData[$value['type_id']]['num'] += $value['num'];
                }
                else {
                    $typeData[] = [
                        'type_id' => $value['type_id'],
                        'num' => $value['num']
                    ];
                }
            }
        }

        $arr = [];
        foreach($typeData as $vv) {
            if(!isset($arr[$vv['type_id']])) {
                $arr[$vv['type_id']] = $vv;
            }
            else {
                $arr[$vv['type_id']]['num'] += $vv['num'];
            }
        }

        foreach($arr as $v) {
            ProductSlaveContentModel::where([
                'type_id' => $v['type_id'],
                'product_order_id' => $productOrderId,
            ])
                ->update(['actual_num' => $v['num']]);
        }

        return $productOrderId;
    }

    private static function checkTypeInfo($taskContent, $materielContent)
    {
        $arr = [];
        foreach($taskContent as $value) {
            if($value['is_product_materiel']) {
                $contentInfo = MaterielProductContentModel::select(
                    'a.*',
                    'b.materiel_name',
                    'b.type_name',
                    'c.materiel_name as product_name',
                    'c.type_name as product_type',
                )
                    ->from('materiel_product_content as a')
                    ->leftJoin('materiel_type as b', 'b.id', '=', 'a.type_id')
                    ->leftJoin('materiel_type as c', 'c.id', '=', 'a.product_id')
                    ->where('product_id', $value['type_id'])->get()->toArray();

                foreach($contentInfo as $val) {
                    $arr[] = [
                        'type_id' => $val['type_id'],
                        'num' => $val['num'] * $value['num'],
                        'product_id' => $val['product_id'],
                        'materiel_name' => $val['materiel_name'],
                        'type_name' => $val['type_name'],
                        'is_product_content' => 1,
                        'product_name' => $val['product_name'],
                        'product_type' => $val['product_type']
                    ];
                }
            }
            else {
                $materielTypeInfo = MaterielTypeModel::where('id', $value['type_id'])->first();

                $arr[] = [
                    'type_id' => $value['type_id'],
                    'num' => $value['num'],
                    'materiel_name' => $materielTypeInfo['materiel_name'],
                    'type_name' => $materielTypeInfo['type_name'],
                    'is_product_content' => 0,
                ];
            }
        }

        $arr1 = [];
        foreach($materielContent as $v) {
            $materielTypeInfo = MaterielTypeModel::where('id', $v['type_id'])->first();

            if($materielTypeInfo['is_use_serial']) {
                 if(empty($v['serial_info'])) {
                     throw new Exception('商品:'.$materielTypeInfo['materiel_name'].'-'.
                         $materielTypeInfo['type_name'].'已开启序列号,请选择序列号后操作');
                 }
                 else {
                     if($v['num'] < count($v['serial_info'])) {
                         throw new Exception('商品:'.$materielTypeInfo['materiel_name'].'-'.
                             $materielTypeInfo['type_name'].'所需序列号数量x'.$v['num'].',尚缺x'.($v['num'] - count($v['serial_info'])));
                     }
                 }
            }

            $arr1[] = [
                'type_id' => $v['type_id'],
                'num' => $v['num']
            ];
        }

        $newArr = [];
        foreach($arr as $arrVal) {
            if(!isset($newArr[$arrVal['type_id']])) {
                $newArr[$arrVal['type_id']] = $arrVal;
            }
            else {
                $newArr[$arrVal['type_id']]['num'] += $arrVal['num'];
            }
        }

        foreach($newArr as &$v1) {
            $searchArray = array_search($v1['type_id'], array_column($arr1, 'type_id'));

            if(strlen($searchArray) === 0) {
                throw new Exception('任务:' . $v1['materiel_name'] . '-' . $v1['materiel_name'] . '当前所需原料' . 'x' . $v1['num'] . ',原料尚缺x' . $v1['num']);
            }

            foreach ($arr1 as &$v2) {
                $result = array_search($v1['type_id'], $v2);

//                if ($result !== 'type_id') {
//                    throw new Exception('任务:' . $v1['materiel_name'] . '-' . $v1['materiel_name'] . '当前所需原料' . 'x' . $v1['num'] . ',原料尚缺x' . $v1['num']);
//                }

                if ($v1['is_product_content']) {
                    if ($v1['type_id'] == $v2['type_id']) {
                        if ($v1['num'] > $v2['num']) {
                            $shortNum = $v1['num'] - $v2['num'];

                            throw new Exception('任务:' . $v1['product_name'] . '-' . $v1['product_type'] .
                                '当前所需套件:' . $v1['materiel_name'] . '-' . $v1['type_name'] . 'x' . $v1['num'] .
                                ',原料尚缺x' . $shortNum);
                        } else {
                            $shortNum = $v2['num'] - $v1['num'];
                            $v2['num'] -= $v1['num'];
                        }
                    }
                } else {
                    if ($v1['type_id'] == $v2['type_id']) {
                        if ($v1['num'] > $v2['num']) {
                            $shortNum = $v1['num'] - $v2['num'];
                            throw new Exception('任务:' . $v1['materiel_name'] . '-' . $v1['materiel_name'] .
                                '当前所需原料' . 'x' . $v1['num'] .
                                ',原料尚缺x' . $shortNum);
                        }
                    }
                }
            }
        }

        return true;
    }

    //检查生产原料信息-普通
    private static function checkContentInfo($materielContent)
    {
        foreach($materielContent as $value) {
            if($value['num'] == 0) {
                throw new Exception('生产原料数量不能为0');
            }

            $materielInfo = MaterielTypeModel::getInfo($value['type_id']);

            $num = 0;
            //是否开启序列号
            if($materielInfo['is_use_serial']) {
                if(empty($value['serial_info'])) {
                    throw new Exception('商品'.$materielInfo['materiel_name'].'-'.$materielInfo['type_name'].'已开启序列号，请选择序列号');
                }

                foreach($value['serial_info'] as $serialVal) {
                    $serialInfo = SerialNumberModel::where('id', $serialVal['serial_id'])->first();

                    if($serialInfo['status'] == 0) {
                        throw new Exception('序列号:'.$serialInfo['serial_no'].'已被使用');
                    }

                    $storageManageInfo = StorageManageModel::where('id', $serialVal['storage_manage_id'])->first();

                    if(empty($storageManageInfo)) {
                        throw new Exception('无效库存，请重试');
                    }

                    if($serialVal['num'] > $storageManageInfo['virtual_storage_num']) {
                        throw new Exception('序列号：'.$serialInfo['serial_no'].'对应的可用库存数量不足，当前所需数量为：'.$serialVal['num'].',当前可用库存为:'.$storageManageInfo['virtual_storage_num']);
                    }

                    $num += $serialVal['num'];
                }
            }
            else {
                foreach($value['storage_manage_info'] as $storageManageVal) {
                    $storageManageInfo = StorageManageModel::where('id', $storageManageVal['storage_manage_id'])->first();

                    if(empty($storageManageInfo)) {
                        throw new Exception('无效库存，请重试');
                    }

                    if($storageManageVal['num'] > $storageManageInfo['virtual_storage_num']) {
                        throw new Exception('商品：'.$materielInfo['materiel_name'].'-'.$materielInfo['type_name'].'对应的可用库存数量不足，当前所需数量为：'.$storageManageVal['num'].',当前可用库存为:'.$storageManageInfo['virtual_storage_num']);
                    }

                    $num += $storageManageVal['num'];
                }
            }

            if($value['num'] > $num) {
                throw new Exception('商品:'.$materielInfo['materiel_name'].'-'.
                    $materielInfo['type_name'].'所需序列号数量x'.$value['num'].',尚缺x'.($value['num'] - $num));
            }
        }

        return true;
    }

    //检查生产原料信息-还库
    private static function checkContentInfoForBalance($materielContent)
    {
        foreach($materielContent as $value) {
            if($value['num'] == 0) {
                throw new Exception('生产原料数量不能为0');
            }

            $materielInfo = MaterielTypeModel::getInfo($value['type_id']);

            $num = 0;
            //是否开启序列号
            if($materielInfo['is_use_serial']) {
                if(empty($value['serial_info'])) {
                    throw new Exception('商品'.$materielInfo['materiel_name'].'-'.$materielInfo['type_name'].'已开启序列号，请填写序列号');
                }

                foreach($value['serial_info'] as $serialVal) {
                    $serialInfo = SerialNumberModel::where('id', $serialVal['serial_id'])->first();

                    if($serialInfo['status'] == 1) {
                        throw new Exception('序列号:'.$serialInfo['serial_no'].'未被使用，无法还库');
                    }

                    $storageManageInfo = StorageManageModel::where('id', $serialVal['storage_manage_id'])->first();

                    if(empty($storageManageInfo)) {
                        throw new Exception('无效库存，请重试');
                    }

                    $num += $serialVal['num'];
                }
            }
            else {
                foreach($value['storage_manage_info'] as $storageManageVal) {
                    $storageManageInfo = StorageManageModel::where('id', $storageManageVal['storage_manage_id'])->first();

                    if(empty($storageManageInfo)) {
                        throw new Exception('无效库存，请重试');
                    }

                    $num += $storageManageVal['num'];
                }
            }

            if($value['num'] > $num) {
                throw new Exception('商品:'.$materielInfo['materiel_name'].'-'.
                    $materielInfo['type_name'].'所需序列号数量x'.$value['num'].',尚缺x'.($value['num'] - $num));
            }

            if($value['num'] < $num) {
                throw new Exception('商品:'.$materielInfo['materiel_name'].'-'.
                    $materielInfo['type_name'].'所需序列号数量x'.$value['num'].',超出'.($num - $value['num']));
            }
        }

        return true;
    }

    public static function balanceList(array $all)
    {
        $productSlaveContentStorageInfo = ProductSlaveContentStorageModel::select(
            'a.*',
//            'f.serial_no',
            'b.storage_name',
            'b.storage_address',
            'c.shelf_name',
            'b.shelf_id',
            'd.location_name',
            'b.location_id',
            'e.materiel_name',
            'e.type_name',
            'e.is_use_serial',
            'a.total_storage_num',
            'a.handle_num',
        )
            ->from('product_slave_content_storage as a')
            ->leftJoin('storage_manage as b', 'b.id', '=', 'a.storage_manage_id')
            ->leftJoin('storage_shelf as c', 'c.id', '=', 'b.shelf_id')
            ->leftJoin('storage_shelf_location as d', 'd.id', 'b.location_id')
            ->leftJoin('materiel_type as e', 'e.id', '=', 'a.type_id')
            ->where('a.is_out', 0)
//            ->leftJoin('serial_number as f', 'f.id', '=', 'a.serial_id')
//            ->where('f.status', 0)
//            ->where('flag', 0)
            ->where('product_order_id', $all['id'])->get()->toArray();

        $arr = [];
        if(!empty($productSlaveContentStorageInfo))  {
            foreach ($productSlaveContentStorageInfo as $val){

                $info = ProductSlaveContentModel::where(['product_order_id'=>$val['product_order_id'],'type_id'=>$val['type_id']])->first();
                if(!empty($info)) {
                    $arr[$val['type_id']]['type_id'] = $val['type_id'];
                    $arr[$val['type_id']]['materiel_name'] = $val['materiel_name'];
                    $arr[$val['type_id']]['type_name'] = $val['type_name'];
                    $arr[$val['type_id']]['is_use_serial'] = $val['is_use_serial'];
                    $arr[$val['type_id']]['actual_num'] = $info['actual_num'];
                    $arr[$val['type_id']]['rest_handle_num'] = $info['num'] - $info['actual_num'] - $info['handle_num'];

                    if($val['is_use_serial']) {
                        $serialInfo = SerialNumberModel::where([
                            'id' => $val['serial_id'],
                            'status' => 0
                        ])->first();

                        if(!empty($serialInfo)) {
                            $arr[$val['type_id']]['storage_manage_info'][] = [
                                'serial_id' => $val['serial_id'],
                                'serial_no' => empty($serialInfo['serial_no'])?'':$serialInfo['serial_no'],
                                'storage_manage_id' => $val['storage_manage_id'],
                                'storage_name' => $val['storage_name'],
                                'storage_address' => $val['storage_address'],
                                'total_storage_num' => $val['total_storage_num'],
                                'handle_num' => $val['handle_num'],
                                'shelf_name' => $val['shelf_name'],
                                'location_name' => $val['location_name'],
                            ];
                        }
                    }
                    else {
                        $arr[$val['type_id']]['storage_manage_info'][] = [
                            'serial_id' => 0,
                            'serial_no' => '',
                            'storage_manage_id' => $val['storage_manage_id'],
                            'storage_name' => $val['storage_name'],
                            'storage_address' => $val['storage_address'],
                            'total_storage_num' => $val['total_storage_num'],
                            'handle_num' => $val['handle_num'],
                            'shelf_name' => $val['shelf_name'],
                            'location_name' => $val['location_name'],
                        ];
                    }
                }
            }
        }
        return array_values($arr);
    }

    //检查生产原料是否足够完成生产任务
    private static function compareTaskAndContent($taskContent, $materielContent)
    {
        foreach($taskContent['task_materiel_num'] as $key => $value) {
            foreach($materielContent as $val) {
                if($key == $val['type_id']) {
                    $materialTypeModel = MaterielTypeModel::where('id', $val['type_id'])->first();
                    if($value > $val['num']) {
                        throw new Exception(
                            '生产原料:'.$materialTypeModel['materiel_name'].
                            '-'.$materialTypeModel['type_name'].'所需数量为:'.
                            $value.$materialTypeModel['materiel_unit'].',目前还需:'.($value - $val['num']).$materialTypeModel['materiel_unit']
                        );
                    }
                }
            }
        }

        return true;
    }

    //创建生产订单主单
    private static function addProduct($num, array $data, $relationNo)
    {
        return ProductOrderModel::insertGetId([
            'product_no' => 'p'.self::createProductNo(),
            'total_num' => $num,
            'product_source' => $data['product_source'],
            'relation_no' => $relationNo,
            'product_source_id' => $data['product_source_id'],
            'product_way' => $data['product_way'],
            'user_id' => $data['user_id'],
            'main_id' => $data['main_id'],
            'created_at' => time()
        ]);
    }

    //创建单号
    private static function createProductNo()
    {
        list($t1, $t2) = explode(' ', microtime());
        $str =(float)sprintf('%.0f', (floatval($t1) + floatval($t2)) * 1000);
        $millisecond = substr($str,10,13);
        $date = date("YmdHis").$millisecond.mt_rand(100000,999999);

        return $date;
    }

    //创建生产订单子单
    private static function addProductSlave($taskContent, $productOrderId, $data)
    {
        $slaveData = [];
        foreach($taskContent as $value) {
            $slaveData[] = [
                'product_order_id' => $productOrderId,
                'is_product_materiel' => $value['is_product_materiel'],
                'type_id' => $value['type_id'],
                'num' => $value['num'],
                'main_id' => $data['main_id'],
                'created_at' => time()
            ];
        }

        ProductSlaveModel::insert($slaveData);
    }

    //创建生产订单原料
    private static function addProductContent($data, $materielContent, $productOrderId)
    {
        $slaveContentData = [];
        $slaveContentStorageData = [];
        $storageManageData = [];
        foreach($materielContent as $value) {
            $slaveContentData = [
                'product_order_id' => $productOrderId,
                'type_id' => $value['type_id'],
                'product_source' => $data['product_source'],
                'product_source_id' => $data['product_source_id'],
                'num' => $value['num'],
                'main_id' => $data['main_id'],
                'created_at' => time()
            ];

            //生成生产原料绑定的库存信息
            $contentId = ProductSlaveContentModel::insertGetId($slaveContentData);

            $materielInfo = MaterielTypeModel::getInfo($value['type_id']);

            if($materielInfo['is_use_serial']) {
                if(!is_integer($value['num'])) {
                    throw new Exception('序列号商品数量不能为小数');
                }
                foreach($value['serial_info'] as $vals) {
                    //货架及库位处理s
                    $storageManageInfo = StorageManageModel::where('id', $vals['storage_manage_id'])->first();

                    if($vals['num'] > $storageManageInfo['virtual_storage_num']) {
                        throw new Exception('商品:'.$storageManageInfo['materiel_name'].'可用库存数('.$storageManageInfo['virtual_storage_num'].')不足,操作数量:'.$vals['num']);
                    }

                    StorageManageModel::where('id', $vals['storage_manage_id'])
                        ->update([
                            'virtual_storage_num' => $storageManageInfo['virtual_storage_num'] - $vals['num'],
                        ]);

                    $slaveContentStorageData[] = [
                        'product_order_id' => $productOrderId,
                        'type_id' => $value['type_id'],
                        'product_slave_content_id' => $contentId,
                        'serial_id' => $vals['serial_id'],
                        'storage_manage_id' => $vals['storage_manage_id'],
                        'shelf_id' => $storageManageInfo['shelf_id'],
                        'location_id' => $storageManageInfo['location_id'],
                        'main_id' => $data['main_id'],
                        'created_at' => time(),
                        'num' => $vals['num'],
                        'total_storage_num' => $vals['num'],
                        'storage_operate_num' => 0
                    ];
                }
            }
            else{
                foreach($value['storage_manage_info'] as $val) {
                    $storageManageInfo = StorageManageModel::where('id', $val['storage_manage_id'])->first();
                    //货架及库位处理
                    if(!isset($vals['location_id'])) {
                        $shelfInfo = StorageShelfModel::query()->where('storage_id', $val['storage_id'])->where('shelf_type', 1)->first();
                        $locationInfo = StorageShelfLocationModel::where([
                            'shelf_id' => $shelfInfo['id'],
                            'location_type' => 1
                        ])->first();

                        $shelfId = $shelfInfo['id'];
                        $locationId = $locationInfo['id'];
                    }
                    else {
                        $shelfId = $data['shelf_id'];
                        $locationId = $data['location_id'];
                    }

                    if($val['num'] > $storageManageInfo['virtual_storage_num']) {
                        throw new Exception('商品:'.$storageManageInfo['materiel_name'].'可用库存数('.$storageManageInfo['virtual_storage_num'].')不足,操作数量:'.$val['num']);
                    }

                    $storageManageData[] = [
                        'id' => $storageManageInfo['id'],
                        'virtual_storage_num' => $storageManageInfo['virtual_storage_num'] - $val['num'],
                    ];

                    $slaveContentStorageData[] = [
                        'product_order_id' => $productOrderId,
                        'type_id' => $value['type_id'],
                        'product_slave_content_id' => $contentId,
                        'serial_id' => 0,
                        'storage_manage_id' => $val['storage_manage_id'],
                        'shelf_id' => $shelfId,
                        'location_id' => $locationId,
                        'main_id' => $data['main_id'],
                        'created_at' => time(),
                        'num' => $val['num'],
                        'total_storage_num' => $val['num'],
                        'storage_operate_num' => 0
                    ];
                }
            }
        }

        //生成生产原料绑定的库存信息
        ProductSlaveContentStorageModel::insert($slaveContentStorageData);

        if(!empty($storageManageData)) {
            batch()->update(new StorageManageModel, $storageManageData, 'id');
        }

        return true;
    }

    //删除
    public static function del($id, int $mainId)
    {
        $info = ProductOrderModel::detail($id, $mainId);

        if(empty($info)) {
            return ['code' => 1, 'msg' => '无效的目标单据，请刷新后重试', 'data' => ''];
        }

        if($info['product_status']) {
            return ['code' => 1, 'msg' => '订单正在生产中，无法删除，请重试', 'data' => ''];
        }

        $info->delete_flag = 1;
        $info->save();

        return ['code' => 0, 'msg' => 'success', 'data' => ''];
    }

    //生产订单列表
    public static function aaaa(array $data, array $condition, $keyword, $startTime, $endTime)
    {
        if($data['search_type'] != 0) {
            switch($data['search_type']) {
                case 1://商品名
                    $result = self::searchByMaterielName($data, $condition, $keyword, $startTime, $endTime);
                    break;
                case 2://规格名
                    $result = self::searchByTypeName($data, $condition, $keyword, $startTime, $endTime);
                    break;
                case 3://商品编号
                    $result = self::searchByMaterielNo($data, $condition, $keyword, $startTime, $endTime);
                    break;
                case 4://内部单号
                    $result = self::searchByOrderNo($data, $condition, $keyword, $startTime, $endTime);
                    break;
                case 5://关联单号
                    $result = self::searchByRelationNo($data, $condition, $keyword, $startTime, $endTime);
                    break;
                case 6://操作人
                    $result = self::searchByOperator($data, $condition, $keyword, $startTime, $endTime);
                    break;
            }
        }
        else {
            //全部
            $result = self::searchAll($data, $condition, $keyword, $startTime, $endTime);
        }

        return $result;
    }

    //生产订单列表-商品名
    private static function searchByMaterielName(array $data, array $condition, $keyword, $startTime, $endTime)
    {
        //从子单获取主单id
        $slaveGetOrderIdInfo = ProductOrderModel::searchByMaterielNameInSlave($data, $condition, $keyword, $startTime, $endTime);
        //从子单内容表获取主单id
        $slaveContentGetOrderIdInfo = ProductOrderModel::searchByMaterielNameInSlaveContent($data, $condition, $keyword, $startTime, $endTime);

        //组装生产订单主id
        $orderId = self::assianOrderId($slaveGetOrderIdInfo, $slaveContentGetOrderIdInfo);

        return self::commonSearch($orderId, $data);
    }

    private static function commonSearch(array $orderId, array $data)
    {
        return ProductOrderModel::list($orderId, $data);
    }

    //生产订单列表-规格名
    private static function searchByTypeName(array $data, array $condition, $keyword, $startTime, $endTime)
    {
        //从子单获取主单id
        $slaveGetOrderIdInfo = ProductOrderModel::searchByTypeNameInSlave($data, $condition, $keyword, $startTime, $endTime);
        //从子单内容表获取主单id
        $slaveContentGetOrderIdInfo = ProductOrderModel::searchByTypeNameInSlaveContent($data, $condition, $keyword, $startTime, $endTime);

        //组装生产订单主id
        $orderId = self::assianOrderId($slaveGetOrderIdInfo, $slaveContentGetOrderIdInfo);

        return self::commonSearch($orderId, $data);
    }

    //生产订单列表-商品编号
    private static function searchByMaterielNo(array $data, array $condition, $keyword, $startTime, $endTime)
    {
        //从子单获取主单id
        $slaveGetOrderIdInfo = ProductOrderModel::searchByMaterielNoInSlave($data, $condition, $keyword, $startTime, $endTime);
        //从子单内容表获取主单id
        $slaveContentGetOrderIdInfo = ProductOrderModel::searchByMaterielNoInSlaveContent($data, $condition, $keyword, $startTime, $endTime);

        //组装生产订单主id
        $orderId = self::assianOrderId($slaveGetOrderIdInfo, $slaveContentGetOrderIdInfo);

        return self::commonSearch($orderId, $data);
    }

    //生产订单列表-内部单号
    private static function searchByOrderNo(array $data, array $condition, $keyword, $startTime, $endTime)
    {
        //从主单获取id
        $orderIdInfo = ProductOrderModel::searchByProductNoInOrder($data, $condition, $keyword, $startTime, $endTime);

        $orderId = [];
        foreach($orderIdInfo as $value) {
            $orderId[] = $value['id'];
        }

        return self::commonSearch($orderId, $data);
    }

    //生产订单列表-关联单号
    private static function searchByRelationNo(array $data, array $condition, $keyword, $startTime, $endTime)
    {
        //从主单获取id
        $orderIdInfo = ProductOrderModel::searchByRelationNoInOrder($data, $condition, $keyword, $startTime, $endTime);

        $orderId = [];
        foreach($orderIdInfo as $value) {
            $orderId[] = $value['id'];
        }

        return self::commonSearch($orderId, $data);
    }

    //生产订单列表-操作人
    private static function searchByOperator(array $data, array $condition, $keyword, $startTime, $endTime)
    {
        //从主单获取id
        $orderIdInfo = ProductOrderModel::searchByOperatorInOrder($data, $condition, $keyword, $startTime, $endTime);

        $orderId = [];
        foreach($orderIdInfo as $value) {
            $orderId[] = $value['id'];
        }

        return self::commonSearch($orderId, $data);
    }

    //生产订单列表-全部
    private static function searchAll(array $data, array $condition, $keyword, $startTime, $endTime)
    {
        if(empty($keyword)) {
            //无关键词
            $result = self::searchAllWithOutKeyword($data, $condition, $startTime, $endTime);
        }
        else {
            //有关键词
            $result = self::searchAllWithKeyword($data, $condition, $keyword, $startTime, $endTime);
        }

        return $result;
    }

    //生产订单列表-全部-无关键词
    private static function searchAllWithOutKeyword(array $data, array $condition, $startTime, $endTime)
    {
        $orderIdInfo = ProductOrderModel::searchAllWithOutKeyword($data, $condition, $startTime, $endTime);

        $orderId = [];
        foreach($orderIdInfo as $value) {
            $orderId[] = $value['id'];
        }

        return self::commonSearch($orderId, $data);
    }

    //生产订单列表-全部-有关键词
    private static function searchAllWithKeyword(array $data, array $condition, $keyword, $startTime, $endTime)
    {
        //从子单获取主单id-商品名
        $slaveMaterielInfo = ProductOrderModel::searchByMaterielNameInSlave($data, $condition, $keyword, $startTime, $endTime);
        //从子单内容表获取主单id-商品名
        $slaveContentMaterielInfo = ProductOrderModel::searchByMaterielNameInSlaveContent($data, $condition, $keyword, $startTime, $endTime);
        //从子单获取主单id-规格名
        $slaveTypeInfo = ProductOrderModel::searchByTypeNameInSlave($data, $condition, $keyword, $startTime, $endTime);
        //从子单内容表获取主单id-规格名
        $slaveContentTypeInfo = ProductOrderModel::searchByTypeNameInSlaveContent($data, $condition, $keyword, $startTime, $endTime);
        //从子单获取主单id-商品编号
        $slaveMaterielNoInfo = ProductOrderModel::searchByMaterielNoInSlave($data, $condition, $keyword, $startTime, $endTime);
        //从子单内容表获取主单id-商品编号
        $slaveContentMaterielNoInfo = ProductOrderModel::searchByMaterielNoInSlaveContent($data, $condition, $keyword, $startTime, $endTime);
        //从主单获取id-生产单编号
        $productNoInfo = ProductOrderModel::searchByProductNoInOrder($data, $condition, $keyword, $startTime, $endTime);
        //从主单获取id-关联单号
        $relationNoInfo = ProductOrderModel::searchByRelationNoInOrder($data, $condition, $keyword, $startTime, $endTime);
        //从主单获取id
        $operatorInfo = ProductOrderModel::searchByOperatorInOrder($data, $condition, $keyword, $startTime, $endTime);

        $orderId = self::assianOrderId(
            $slaveMaterielInfo,
            $slaveContentMaterielInfo,
            $slaveTypeInfo,
            $slaveContentTypeInfo,
            $slaveMaterielNoInfo,
            $slaveContentMaterielNoInfo,
            $productNoInfo,
            $relationNoInfo,
            $operatorInfo,
        );

        return self::commonSearch($orderId, $data);
    }

    //组装id
    private static function assianOrderId($arr, $arr1, $arr2 = [], $arr3 = [], $arr4 = [], $arr5 = [], $arr6 = [], $arr7 = [], $arr8 = [])
    {
        $orderId = [];
        if(!empty($arr)) {
            foreach($arr as $value) {
                if(!in_array($value['id'], $orderId)) {
                    array_push($orderId, $value['id']);
                }
            }
        }

        if(!empty($arr1)) {
            foreach ($arr1 as $val) {
                if(!in_array($val['id'], $orderId)) {
                    array_push($orderId, $val['id']);
                }
            }
        }

        if(!empty($arr2)) {
            foreach($arr2 as $value) {
                if(!in_array($value['id'], $orderId)) {
                    array_push($orderId, $value['id']);
                }
            }
        }

        if(!empty($arr3)) {
            foreach ($arr3 as $val) {
                if(!in_array($val['id'], $orderId)) {
                    array_push($orderId, $val['id']);
                }
            }
        }

        if(!empty($arr4)) {
            foreach($arr4 as $v) {
                if(!in_array($v['id'], $orderId)) {
                    array_push($orderId, $v['id']);
                }
            }
        }

        if(!empty($arr5)) {
            foreach ($arr5 as $v1) {
                if(!in_array($v1['id'], $orderId)) {
                    array_push($orderId, $v1['id']);
                }
            }
        }

        if(!empty($arr6)) {
            foreach ($arr6 as $v1) {
                if(!in_array($v1['id'], $orderId)) {
                    array_push($orderId, $v1['id']);
                }
            }
        }

        if(!empty($arr7)) {
            foreach ($arr7 as $v1) {
                if(!in_array($v1['id'], $orderId)) {
                    array_push($orderId, $v1['id']);
                }
            }
        }

        if(!empty($arr8)) {
            foreach ($arr8 as $v1) {
                if(!in_array($v1['id'], $orderId)) {
                    array_push($orderId, $v1['id']);
                }
            }
        }

        return $orderId;
    }

    //撤销
    public static function cancel($data)
    {
        $info = ProductOrderModel::detail($data['id'], $data['main_id']);

        if(empty($info)) {
            return ['code' => 1, 'msg' => '无效生产订单，请重试', 'data' => ''];
        }

        if($info['product_status'] != 0) {
            return ['code' => 1, 'msg' => '仅新创建的生产订单可撤销', 'data' => ''];
        }

        if($info['is_cancel']) {
            return ['code' => 1, 'msg' => '无法重复撤销', 'data' => ''];
        }

//        $findFillInfo = ProductFillOrBalanceContentModel::where('product_order_id', $data['id'])->get()->toArray();
        //查看有无生产订单不足信息
        $findFillContentInfo = ProductFillOrBalanceContentModel::where([
            'type' => 0,
            'product_order_id' => $data['id']
        ])->get()->toArray();

        $findProductSlaveContentInfo = ProductSlaveContentStorageModel::select(
            'storage_manage_id',
            DB::raw('SUM(num) as num')
        )
            ->where('flag', 0)
            ->where('product_order_id', $data['id'])
            ->groupBy('storage_manage_id')
            ->get()->toArray();

        DB::beginTransaction();

        try {
            $info->is_cancel = 1;
            $info->save();
            $serialInfo = [];
            if(!empty($findFillContentInfo)) {
                //变更生产订单的出库撤销状态为已撤销
                LogOutStorageModel::where([
                    'all_id_type' => 3,
                    'all_id' => $data['id']
                ])
                    ->update(['is_cancel' => 1]);

//                //获取补足商品库存信息
//                $findFillContentInfo = ProductFillOrBalanceContentModel::where('product_order_id', $data['id'])->get()->toArray();


                foreach($findFillContentInfo as $value) {
                    //退回库存
                    StorageManageModel::where('id', $value['storage_manage_id'])
                        ->update([
                            'in_storage_num' => DB::raw('in_storage_num + '.$value['num']),
                            'virtual_storage_num' => DB::raw("virtual_storage_num + ".$value['num']),
                            'delete_flag' => 0
                        ]);

                    $serialInfo[] = [
                        'id' => $value['serial_id'],
                        'status' => 1
                    ];
                }

                if($info['product_source_id'] != 0) {
                    SellModel::where('id', $info['product_source_id'])->update(['has_product_order' => 0]);
                }
            }

            $storageManageData = [];
            if(!empty($findProductSlaveContentInfo)) {
                foreach($findProductSlaveContentInfo as $val) {
                    $storageManageInfo = StorageManageModel::where('id', $val['storage_manage_id'])->first();

                    $storageManageData[] = [
                        'id' => $storageManageInfo['id'],
                        'virtual_storage_num' => $storageManageInfo['virtual_storage_num'] + $val['num'],
                    ];
                }
            }

            //退回序列号
            if(!empty($serialInfo)) {
                batch()->update(new SerialNumberModel, $serialInfo, 'id');
            }

            if(!empty($storageManageData)) {
                batch()->update(new StorageManageModel, $storageManageData, 'id');
            }

            DB::commit();
            return ['code' => 0, 'msg' => 'success', 'data' => ''];
        }
        catch(Exception $e) {
            Log::debug('生产订单撤销:'.var_export($e->getMessage(), true));
            DB::rollBack();
            return ['code'];
        }
    }

    //重新下单
    public static function again(array $data)
    {
        $info = ProductOrderModel::detail1($data['id'], $data['main_id'])->toArray();

        if(empty($info)) {
            return ['code' => 1, 'msg' => '无效生产订单，请重试', 'data' => ''];
        }

        if($info['is_cancel']) {
            return ['code' => 1, 'msg' => '目标订单已撤销，无法下单', 'data' => ''];
        }

        if($info['product_source'] != 0) {
            return ['code' => 1, 'msg' => '仅普通订单可重新下单', 'data' => ''];
        }

        $arr = [
            'product_no' => 'p'.self::createProductNo(),
            'product_status' => 0,
            'product_source' => $info['product_source'],
            'product_source_id' => $info['product_source_id'],
            'total_num' => $info['total_num'],
            'relation_no' => $info['relation_no'],
            'product_way' => $info['product_way'],
            'is_cancel' => 0,
            'main_id' => $info['main_id'],
            'user_id' => $info['user_id'],
            'created_at' => time()
        ];

        DB::beginTransaction();

        try {
            $orderId = ProductOrderModel::insertGetId($arr);

            $slaveData = [];
            foreach($info['slave_info'] as $value) {
                $slaveData[] = [
                    'product_order_id' => $orderId,
                    'is_product_materiel' => $value['is_product_materiel'],
                    'type_id' => $value['type_id'],
                    'num' => $value['num'],
                    'main_id' => $info['main_id'],
                    'created_at' => time()
                ];
            }

            ProductSlaveModel::insert($slaveData);

            $slaveContentData = [];
            foreach($info['slave_content'] as $val) {
                $slaveContentData[] = [
                    'product_order_id' => $orderId,
                    'type_id' => $val['type_id'],
                    'product_source' => $val['product_source'],
                    'product_source_id' => $val['product_source_id'],
                    'product_slave_id' => $val['product_slave_id'],
                    'num' => $val['num'],
                    'main_id' => $info['main_id'],
                    'created_at' => time()
                ];
            }

            ProductSlaveContentModel::insert($slaveContentData);

            $slaveContentStorage = [];
            foreach($info['slave_content_storage'] as $vals) {
                $slaveContentStorage[] = [
                    'product_order_id' => $orderId,
                    'type_id' => $vals['type_id'],
                    'serial_id' => $vals['serial_id'],
                    'storage_manage_id' => $vals['storage_manage_id'],
                    'num' => $vals['num'],
                    'storage_operate_num' => 0,
                    'main_id' => $info['main_id'],
                    'created_at' => time()
                ];
            }

            DB::commit();
            return ['code' => 0, 'msg' => 'success', 'data' => ''];
        }
        catch(Exception $e) {
            DB::rollBack();
            Log::debug('生产订单重新下单异常:'.var_export($e->getMessage()));
            return ['code' => 1, 'msg' => '生产订单重新下单异常', 'data' => ''];
        }
    }

    //详细
    public static function detail($id)
    {
        $mainInfo = ProductOrderModel::detail($id);

        $slaveContentInfo = ProductSlaveContentModel::select(
            'a.id',
            'a.type_id',
            'a.num',
            'a.actual_num',
            'a.storage_operate_num',
            'b.type_name',
            'b.materiel_name',
            'b.materiel_unit',
            'b.is_use_serial',
            'a.handle_num'
        )
            ->from('product_slave_content as a')
            ->leftJoin('materiel_type as b', 'b.id', '=', 'a.type_id')
            ->where('product_order_id', $id)->get()->toArray();

        $slaveContentStorageInfo = ProductSlaveContentStorageModel::select(
            'product_slave_content_storage.id',
            'product_slave_content_storage.product_order_id',
            'product_slave_content_storage.type_id',
//            'a.type_name',
//            'a.materiel_name',
//            'a.materiel_unit',
//            'a.is_use_serial',
            'c.storage_name',
            'c.storage_address',
            'd.shelf_name',
            'e.location_name',
            'g.serial_no',
            'product_slave_content_storage.serial_id',
            'product_slave_content_storage.storage_manage_id',
            'product_slave_content_storage.storage_operate_num',
            'product_slave_content_storage.num',
            'b.in_storage_num',
            'product_slave_content_storage.delete_flag'
        )
            ->leftJoin('materiel_type as a', 'a.id', '=', 'product_slave_content_storage.type_id')
            ->leftJoin('storage_manage as b', 'b.id', '=', 'product_slave_content_storage.storage_manage_id')
            ->leftJoin('storage as c', 'c.id', '=', 'b.storage_id')
            ->leftJoin('storage_shelf as d', 'd.id', '=', 'b.shelf_id')
            ->leftJoin('storage_shelf_location as e', 'e.id', '=', 'b.location_id')
            ->leftJoin('serial_number as g', 'g.id', '=', 'product_slave_content_storage.serial_id')
            ->where('product_order_id', $id)
            ->where('product_slave_content_storage.flag', 0)
            ->get()->toArray();

        $arr = [];
        foreach($slaveContentStorageInfo as $k => $v) {
            $arr[$v['type_id']] = [
                'type_id' => $v['type_id'],
            ];
            foreach($slaveContentStorageInfo as $v1) {
                if($v['type_id'] == $v1['type_id']) {
                    $arr[$v1['type_id']]['storage_mange_info'][] = [
                        'type_id' => $v1['type_id'],
                        'storage_name' => $v1['storage_name'],
                        'storage_address' => $v1['storage_address'],
                        'shelf_name' => $v1['shelf_name'],
                        'location_name' => $v1['location_name'],
                        'serial_no' => empty($v1['serial_no'])?'':$v1['serial_no'],
                        'serial_id' => $v1['serial_id'],
                        'storage_manage_id' => $v1['storage_manage_id'],
                        'in_storage_num' => $v1['in_storage_num'],
                        'storage_operate_num' => $v1['storage_operate_num'],
                        'rest_num' => $v1['num'] - $v1['storage_operate_num'],
                        'num' => $v1['num'],
                        'delete_flag' => $v1['delete_flag'],
                    ];
                }
            }
        }

        $arr = array_values($arr);

        foreach($slaveContentInfo as &$value) {
            $value['rest_balance_num'] = $value['num'] - $value['actual_num'] - $value['handle_num'];
            foreach($arr as $val) {
                if($value['type_id'] == $val['type_id']) {
                    $value['slave_content_storage_info'] = $val['storage_mange_info'];
                }
            }
        }
//
//        $prodcutFillInfo = ProductFillOrBalanceContentModel::select(
//            'a.serial_id',
//            'a.type_id',
//            'b.materiel_name',
//            'b.type_name',
//            'a.type',
//            'serial_no',
//            'g.storage_name',
//            'a.num',
//            'b.is_use_serial',
//            'd.shelf_name',
//            'e.location_name'
//        )
//            ->from('product_fill_or_balance_content as a')
//            ->leftJoin('materiel_type as b', 'b.id', '=', 'a.type_id')
//            ->leftJoin('storage_manage as c', 'c.id', '=', 'a.storage_manage_id')
//            ->leftJoin('storage_shelf as d', 'd.id', '=', 'c.shelf_id')
//            ->leftJoin('storage_shelf_location as e', 'e.id', '=', 'c.location_id')
//            ->leftJoin('serial_number as f', 'f.id', '=', 'a.serial_id')
//            ->leftJoin('storage as g', 'g.id', '=', 'c.storage_id')
//            ->where('product_order_id', $id)
//            ->get()->toArray();

        //获取补足信息
        $productFillInfo = ProductFillOrBalanceContentModel::getProductFillOrBalanceInfo($id, 0);
        //获取补足信息
        $productBalanceInfo = ProductFillOrBalanceContentModel::getProductFillOrBalanceInfo($id, 1);

        if(!empty($productFillInfo)) {
            $fillData = [];
            foreach($productFillInfo as $fillKey => $fillVal) {
                $fillData[$fillVal['type_id']]['type_id'] = $fillVal['type_id'];
                $fillData[$fillVal['type_id']]['is_use_serial'] = $fillVal['is_use_serial'];
                $fillData[$fillVal['type_id']]['materiel_name'] = $fillVal['materiel_name'];
                $fillData[$fillVal['type_id']]['type_name'] = $fillVal['type_name'];
                $fillData[$fillVal['type_id']]['materiel_unit'] = $fillVal['materiel_unit'];
                $fillData[$fillVal['type_id']]['type'] = $fillVal['type'];
                $fillData[$fillVal['type_id']]['storage_manage_info'][] = [
                    'serial_id' => $fillVal['serial_id'],
                    'serial_no' => empty($fillVal['serial_no'])?'':$fillVal['serial_no'],
                    'num' => $fillVal['num'],
                    'storage_name' => $fillVal['storage_name'],
                    'shelf_name' => $fillVal['shelf_name'],
                    'location_name' => $fillVal['location_name'],
                ];
            }

            $mainInfo['fill_info'] = array_values($fillData);
        }
        else {
            $mainInfo['fill_info'] = [];
        }

        if(!empty($productBalanceInfo)) {
            $balanceData = [];
            foreach($productBalanceInfo as $fillKey => $balanceVal) {
                $balanceData[$balanceVal['type_id']]['type_id'] = $balanceVal['type_id'];
                $balanceData[$balanceVal['type_id']]['is_use_serial'] = $balanceVal['is_use_serial'];
                $balanceData[$balanceVal['type_id']]['materiel_name'] = $balanceVal['materiel_name'];
                $balanceData[$balanceVal['type_id']]['type_name'] = $balanceVal['type_name'];
                $balanceData[$balanceVal['type_id']]['materiel_unit'] = $balanceVal['materiel_unit'];
                $balanceData[$balanceVal['type_id']]['type'] = $balanceVal['type'];
                $balanceData[$balanceVal['type_id']]['storage_manage_info'][] = [
                    'serial_id' => $balanceVal['serial_id'],
                    'serial_no' => empty($balanceVal['serial_no'])?'':$balanceVal['serial_no'],
                    'num' => $balanceVal['num'],
                    'storage_name' => $balanceVal['storage_name'],
                    'shelf_name' => $balanceVal['shelf_name'],
                    'location_name' => $balanceVal['location_name'],
                ];
            }

            $mainInfo['balance_info'] = array_values($balanceData);
        }
        else {
            $mainInfo['balance_info'] = [];
        }

        $mainInfo['slave_content'] = $slaveContentInfo;

        return $mainInfo;
    }

    public static function finished(array $data)
    {
        $mainOrderInfo = ProductOrderModel::getMainOrderInfo($data['id']);

        $data['product_time'] = empty($data['product_time'])?date('Y-m-d H:i:s'):$data['product_time'];

        $slaveContentStorage = ProductSlaveContentStorageModel::where([
            'product_order_id' => $data['id'],
            'flag' => 0
        ])->get()->toArray();

        DB::beginTransaction();

        try {
            foreach($slaveContentStorage as $storageValue) {
                if($storageValue['serial_id'] != 0) {
                    $storageSerialInfo = SerialNumberModel::where([
                        'id' => $storageValue['serial_id']
                    ])->first();

                    if($storageSerialInfo['status'] == 0) {
                        ProductSlaveContentModel::where([
                            'product_order_id' => $data['id'],
                            'type_id' => $storageValue['type_id']
                        ])
                            ->decrement('num', $storageValue['num']);
                        ProductSlaveContentStorageModel::where('id', $storageValue['id'])->update([
                            'flag' => 1,
                            'delete_flag' => 1
                        ]);
                        return ['code' => 1, 'msg' => '序列号:'.$storageSerialInfo['serial_no'].'已被使用', 'data' => ''];
                    }
                }
                else {
                    $getStorageManageInfo = StorageManageModel::where('id', $storageValue['storage_manage_id'])
                        ->first();

                    if($storageValue['num'] > $getStorageManageInfo['in_storage_num']) {
                        ProductSlaveContentModel::where([
                            'product_order_id' => $data['id'],
                            'type_id' => $storageValue['type_id']
                        ])
                            ->decrement('num', $storageValue['num']);

                        ProductSlaveContentStorageModel::where('id', $storageValue['id'])->update(['flag' => 1]);
                        return [
                            'code' => 1,
                            'msg' => '商品:'.$getStorageManageInfo['materiel_name'].'可用库存补不足,当前可用库存X'.$getStorageManageInfo['in_storage_num'].'操作数量X'.$storageValue['num'],
                            'data' => ''
                        ];
                    }
                }
            }
            $content = json_decode($data['product_info'], true);

            if(empty($content)) {
                throw new Exception('所需生产的任务内容不能为空');
            }

            $slaveData = [];
            $num = 0;
            $history = [];
            foreach($content as $value) {
                //获取任务信息
                $slaveInfo = ProductSlaveModel::where('id', $value['id'])->first();
                $typeInfo = MaterielTypeModel::where('id', $slaveInfo['type_id'])->first();

                if($value['num'] > ($slaveInfo['num'] - $slaveInfo['finished_num'])) {
                    throw new Exception('您输入的数量超出商品'.$typeInfo['materiel_name'].'-'.$typeInfo['materiel_name'].'剩余可生产的任务数');
                }

                //生产任务完成前数据组装
                $slaveData[] = [
                    'id' => $value['id'],
                    'finished_num' => $slaveInfo['finished_num'] + $value['num']
                ];

                $num += $value['num'];

                $history[] = [
                    'product_order_id' => $data['id'],
                    'product_slave_id' => $value['id'],
                    'num' => $value['num'],
                    'before_product_num' => $slaveInfo['finished_num'],
                    'rest_num' => $slaveInfo['num'] - ($slaveInfo['finished_num'] + $value['num']),
                    'user_id' => $data['user_id'],
                    'main_id' => $data['main_id'],
                    'product_source' => $mainOrderInfo['product_source'],
                    'product_source_id' => $mainOrderInfo['product_source_id'],
                    'product_time' => strtotime($data['product_time']),
                    'created_at' => time()
                ];
            }

            if($num != 0) {
                //批量修改生产任务已完成数
                if (!empty($slaveData)) {
                    batch()->update(new ProductSlaveModel, $slaveData, 'id');
                }

                $getProductSlaveInfo = ProductSlaveModel::where('product_order_id', $data['id'])
                    ->whereRaw('num > finished_num')
                    ->first();

                $status = 0;
                if(!empty($getProductSlaveInfo)) {
                    $status = 1;
                    ProductOrderModel::where('id', $data['id'])->update(['product_status' => 1]);
                }
                else {
                    $status = 2;
                    ProductOrderModel::where('id', $data['id'])->update(['product_status' => 2]);
                }

                $mainOrderInfo->save();

                if (!empty($history)) {
                    ProductHistoryModel::insert($history);
                }

                //生产订单中生产任务全部完成时对生产原料出库
                if($status == 2) {
                    self::slaveContentOut($data, $mainOrderInfo);
                }
            }

            DB::commit();
            return ['code' => 0, 'msg' => 'success', 'data' => ''];
        }
        catch(Exception $e) {
            DB::rollBack();
            Log::debug('生产订单生产异常'.var_export($e->getMessage(), true));
            return ['code' => 1, 'msg' => $e->getMessage(), 'data' => ''];
        }
    }

    //生产订单中生产任务全部完成时出库
    private static function slaveContentOut(array $data, $mainOrderInfo)
    {
        $slaveContentStorage = ProductSlaveContentStorageModel::where([
            'product_order_id' => $data['id'],
            'flag' => 0
        ])->get()->toArray();

        if(empty($slaveContentStorage)) {
            throw new Exception('生产订单异常:生产订单无生产原料');
        }

        $storageManageData = [];
        $serialId = [];
        $logData = [];
        foreach($slaveContentStorage as $value) {
            if($value['serial_id'] != 0) {
                $serialInfo = SerialNumberModel::where('id', $value['serial_id'])->first();

                if($serialInfo['status'] == 0) {
                    throw new Exception('序列号:'.$serialInfo['serial_no'].'已被使用，无法用户生产');
                }

                $serialId[] = [
                    'id' => $value['serial_id'],
                    'sell_id' => $mainOrderInfo['product_source_id'],
                    'status' => 0
                ];

                $serialNo = $serialInfo['serial_no'];
            }

            $arr['id'] = $value['storage_manage_id'];
            $storageManageInfo = StorageManageModel::detail($arr);

            if($storageManageInfo['delete_flag'] == 1) {
                throw new Exception('库存商品:'.$storageManageInfo['materiel_name'].'-'.$storageManageInfo['type_name'].'不存在，无法完成生产');
            }

//            if($value['num'] > $storageManageInfo['virtual_storage_num']) {
//                throw new Exception('库存商品:'.$storageManageInfo['materiel_name'].'-'.$storageManageInfo['type_name'].'可用库存数量不足，当前可用库存数为:'.$storageManageInfo['virtual_storage_num']);
//            }

//            $storageManageData[] = [
//                'id' => $value['storage_manage_id'],
//                'in_storage_num' => $storageManageInfo['in_storage_num'] - $value['num'],
//                'virtual_storage_num' => $storageManageInfo['virtual_storage_num'] - $value['num'],
//            ];

            $serialNo = '';

            $logData[] = self::outStorageLog($data, $value['num'], $storageManageInfo, $serialNo, 3);

            $storageManageInfo->in_storage_num = $storageManageInfo['in_storage_num'] - $value['num'];
//            $storageManageInfo->virtual_storage_num = $storageManageInfo['virtual_storage_num'] - $value['num'];
            $storageManageInfo->save();
        }

        //序列号入库-更新已使用序列号状态
        if(!empty($serialId)) {
            batch()->update(new SerialNumberModel, $serialId, 'id');
        }

        //扣除库存
//        if(!empty($storageManageData)) {
//            batch()->update(new StorageManageModel, $storageManageData, 'id');
//        }


        if(!empty($logData)) {
            LogOutStorageModel::insert($logData);
        }

        CommonService::setAlertFlag($data['main_id']);

        return true;
    }

    //出库日志
    private static function outStorageLog($data, $num, $storageManageInfo, $serialNo, $allIdType, $unionCode = '', $remark = '', $type = 0)
    {
        $logData = [
            'type' => $type,
            'storage_id' => $storageManageInfo['storage_id'],
            'storage_name' => $storageManageInfo['storage_name'],
            'storage_address' => $storageManageInfo['storage_address'],
            'curr_storage_manage_id' => $storageManageInfo['id'],
            'materiel_class_id' => $storageManageInfo['s_class_id'],
            'materiel_class_name' => $storageManageInfo['s_class_name'],
            'materiel_class_no' => $storageManageInfo['s_class_no'],
            'materiel_type_id' => $storageManageInfo['type_id'],
            'materiel_name' => $storageManageInfo['materiel_name'],
            'type_name' => $storageManageInfo['type_name'],
            'materiel_no' => $storageManageInfo['materiel_no'],
            'relation_code' => $unionCode,
            'operate_num' => $num,
            'serial_number' => $serialNo,
            'last_storage_num' => $storageManageInfo['in_storage_num'],
            'next_storage_num' => $storageManageInfo['in_storage_num'] - $num,
            'materiel_mean_cost' => $storageManageInfo['materiel_mean_cost'],
            'fact_out_time' => strtotime(date('Y-m-d')),
            'all_id_type' => $allIdType,
            'all_id' => $data['id'],
            'user_id' => $data['user_id'],
            'main_id' => $data['main_id'],
            'out_storage_time' => time(),
            'created_at' => time(),
            'remark' => empty($remark)?'':$remark,
            'shelf_id' => $storageManageInfo['shelf_id'],
            'location_id' => $storageManageInfo['location_id'],
        ];

        MessageService::sendAlertSms(
            $storageManageInfo['materiel_name'],
            $storageManageInfo['type_name'],
            $storageManageInfo['in_storage_num'],
            $storageManageInfo['alert_num'],
            $data,
            $storageManageInfo['storage_id'],
            $storageManageInfo['storage_name'],
            $num
        );

        MessageService::sendShortSms(
            $storageManageInfo['materiel_name'],
            $storageManageInfo['type_name'],
            $storageManageInfo['in_storage_num'],
            $data,
            $storageManageInfo['storage_name'],
            $storageManageInfo['storage_id']
        );

        MessageService::sendOutSms(
            $storageManageInfo['materiel_name'],
            $storageManageInfo['type_name'],
            $storageManageInfo['in_storage_num'],
            $storageManageInfo['storage_name'],
            $num,
            $data,
            $storageManageInfo['storage_id'],
            $storageManageInfo['alert_num']
        );

        return $logData;
    }

    //补足或还库
    public static function fillOrBalance(array $data)
    {
        $unionCode = 'fb'.self::createProductNo();
        /* $taskContent = json_decode($data['task_content'], true); */
        $materielContent = json_decode($data['materiel_content'], true);

        $productInfo = ProductOrderModel::detail($data['id'], $data['main_id']);

        DB::beginTransaction();

        try {
            if(!$data['type']) {//补足
                self::fill($data, /* $taskContent, */ $materielContent, $unionCode);
            }
            else {//还库
                if($productInfo['product_status'] != 2) {
                    return ['code' => 1, 'msg' => '生产订单已完成后才可以结余', 'data' => ''];
                }

                self::balance($data, /* $taskContent,  */$materielContent, $unionCode);
            }

            DB::commit();
            return ['code' => 0, 'msg' => 'success', 'data' => ''];
        }
        catch(Exception $e) {
            DB::rollBack();
            Log::debug('补足或还库异常'.var_export($e->getMessage(), true));
            return ['code' => 1, 'msg' => $e->getMessage(), 'data' => ''];
        }
    }

    //补足
    private static function fill(array $data, /* $taskContent,  */$materielContent, string $unionCode)
    {
        /* $typeInfo = self::checkTypeInfo($taskContent);//检查生产任务信息 */
        self::checkContentInfo($materielContent);//检查生产原料信息
        /* self::compareTaskAndContent($typeInfo, $materielContent);//检查生产原料是否足够完成生产任务 */

        /*   $task = [];
          foreach($taskContent as $value) {
              $task[] = [
                  'type' => $data['type'],
                  'product_order_id' => $data['id'],
                  'type_id' => $value['type_id'],
                  'is_product_materiel' => $value['is_product_materiel'],
                  'num' => $value['num'],
                  'union_code' => $unionCode,
                  'created_at' => time()
              ];
          } */

        $content = [];
        $slaveCondition = [];
        foreach($materielContent as $val) {

            $slaveCondition['type_id'] = $val['type_id'];
            $slaveCondition['product_order_id'] = $data['id'];
            unset($slaveCondition['serial_id']);
            unset($slaveCondition['storage_manage_id']);

            $contentInfo = ProductSlaveContentModel::select('id')->where($slaveCondition)->first()->toArray();

//            ProductSlaveContentModel::where($contentInfo)->increment('num',$val['num']);//生产订单原料表累加

            if(!empty($val['serial_info'])) {
                foreach($val['serial_info'] as $serialVal) {
                    $content[] = [
                        'product_order_id' => $data['id'],
                        'type' => 0,
                        'union_code' => $unionCode,
                        'type_id' => $val['type_id'],
                        'storage_manage_id' => $serialVal['storage_manage_id'],
                        'serial_id' => $serialVal['serial_id'],
                        'num' => $serialVal['num'],
                        'created_at' => time()
                    ];

                    $slaveCondition['serial_id'] = $serialVal['serial_id'];
                    $slaveCondition['storage_manage_id'] = $serialVal['storage_manage_id'];

                    $storageInfo = ProductSlaveContentStorageModel::where($slaveCondition)->first();
                    if(empty($storageInfo)){

                        ProductSlaveContentStorageModel::insertGetId([
                            'product_order_id'         => $data['id'],
                            'type_id'                  => $val['type_id'],
                            'storage_manage_id'        => $serialVal['storage_manage_id'],
                            'serial_id'                => $serialVal['serial_id'],
                            'num'                      => $serialVal['num'],
                            'product_slave_content_id' => $contentInfo['id'],
                            'total_storage_num'        => $serialVal['num'],
                            'main_id'                  => $data['main_id'],
                            'created_at'               => time(),
                            'flag'                     => 1,
                        ]);

                    }
                }
            }else {
                foreach($val['storage_manage_info'] as $storageVal) {
                    $content[] = [
                        'product_order_id' => $data['id'],
                        'union_code' => $unionCode,
                        'type_id' => $val['type_id'],
                        'type' => 0,
                        'storage_manage_id' => $storageVal['storage_manage_id'],
                        'serial_id' => 0,
                        'num' => $storageVal['num'],
                        'created_at' => time()
                    ];

                    //检查补足的库存信息是否存在。不存在则新增ProductSlaveContentStorageModel数据；存在时，则对匹配到的数据`num`进行累加
//                    $slaveCondition['serial_id'] = 0;
                    $slaveCondition['storage_manage_id'] = $storageVal['storage_manage_id'];

                    $storageInfo = ProductSlaveContentStorageModel::where($slaveCondition)->first();

                    if(empty($storageInfo)){
                        unset($slaveCondition['storage_manage_id']);
                        $ContentInfo = ProductSlaveContentModel::select('id')->where($slaveCondition)->first();
                        ProductSlaveContentStorageModel::insert([
                            'product_order_id'         => $data['id'],
                            'type_id'                  => $val['type_id'],
                            'storage_manage_id'        => $storageVal['storage_manage_id'],
                            'serial_id'                => 0,
                            'num'                      => $storageVal['num'],
                            'total_storage_num'        => $storageVal['num'],
                            'product_slave_content_id' => $contentInfo['id'],
                            'main_id'                  => $data['main_id'],
                            'created_at'               => time(),
                            'flag'                     => 1,
                        ]);
                    }
                    else {
                        ProductSlaveContentStorageModel::where($slaveCondition)
                            ->lockForUpdate()
                            ->increment('total_storage_num', $storageVal['num']);
                    }
                }
            }
        }

        //ProductFillOrBalanceModel::insert($task);
        foreach($content as $fillContent) {
            $getFillInfo = ProductFillOrBalanceContentModel::where([
                'product_order_id' => $fillContent['product_order_id'],
                'type_id' => $fillContent['type_id'],
                'serial_id' => $fillContent['serial_id'],
                'type' => 0
            ])->first();

            if(empty($getFillInfo)) {
                ProductFillOrBalanceContentModel::insert($fillContent);
            }
            else {
                $getFillInfo->num = $getFillInfo->num + $fillContent['num'];
                $getFillInfo->save();
            }
        }

        $storageManageData = [];
        $serialId = [];
        $logData = [];
        foreach($content as $vals) {
            if($vals['serial_id'] != 0) {
                $serialInfo = SerialNumberModel::where('id', $vals['serial_id'])->first();

                if($serialInfo['status'] == 0) {
                    throw new Exception('序列号:'.$serialInfo['serial_no'].'已被使用，无法用于补足');
                }

                $serialId[] = [
                    'id' => $vals['serial_id'],
                    'status' => 0
                ];

                $serialNo = $serialInfo['serial_no'];
            }

            $arr['id'] = $vals['storage_manage_id'];
            $storageManageInfo = StorageManageModel::detail($arr);

            if($vals['num'] > $storageManageInfo['virtual_storage_num']) {
                throw new Exception('库存商品:'.$storageManageInfo['materiel_name'].'-'.$storageManageInfo['type_name'].'可用库存数量不足，当前可用库存数为:'.$storageManageInfo['virtual_storage_num']);
            }

            ProductSlaveContentModel::where([
                'product_order_id' => $data['id'],
                'type_id' => $vals['type_id'],
            ])
                ->lockForUpdate()
                ->increment('num', $vals['num']);

            $serialNo = '';

            $logData[] = self::outStorageLog($data, $vals['num'], $storageManageInfo, $serialNo, 3, $unionCode, '', 3);

            $storageManageInfo->in_storage_num = $storageManageInfo->in_storage_num - $vals['num'];
            $storageManageInfo->virtual_storage_num = $storageManageInfo->virtual_storage_num - $vals['num'];
            $storageManageInfo->save();
        }

        //序列号入库-更新已使用序列号状态
        if(!empty($serialId)) {
            batch()->update(new SerialNumberModel, $serialId, 'id');
        }
/*
        //扣除库存
        if(!empty($storageManageData)) {
            batch()->update(new StorageManageModel, $storageManageData, 'id');
        } */


        if(!empty($logData)) {
            LogOutStorageModel::insert($logData);
        }

        CommonService::setAlertFlag($data['main_id']);

        return true;
    }

    //还库

    /**
     * `product_slave_content_storage`中单个原料的总库存和用户还库输入的商品数量的差，不能小于`product_slave_content`中的`num`，该情况下不可以进行还库；
     * 当用户填写的还库数量可以进行还库操作时，需要递归扣除`product_slave_content_storage`中原料对应的num
     */
    private static function balance(array $data,/*  $taskContent, */ $materielContent, string $unionCode)
    {
        /* $typeInfo = self::checkTypeInfo($taskContent);//检查生产任务信息 */

        self::checkContentInfoForBalance($materielContent);//检查生产原料信息
        /* self::compareTaskAndContent($typeInfo, $materielContent);//检查生产原料是否足够完成生产任务 */
/*
        $task = [];
        foreach($taskContent as $value) {
            $task[] = [
                'type' => $data['type'],
                'product_order_id' => $data['id'],
                'type_id' => $value['type_id'],
                'is_product_materiel' => $value['is_product_materiel'],
                'num' => $value['num'],
                'union_code' => $unionCode,
                'created_at' => time()
            ];
        } */

        $content = [];
        $slaveCondition = [];
        foreach($materielContent as $val) {

            $slaveCondition['type_id'] = $val['type_id'];
            $slaveCondition['product_order_id'] = $data['id'];

            $contentInfo = ProductSlaveContentModel::select('id','num','actual_num','handle_num')
                            ->where($slaveCondition)->first()->toArray();

            $materielTypeInfo = MaterielTypeModel::where('id', $val['type_id'])->first();
            //$slaveCondition['product_slave_content_id'] = $contentInfo['id'];
            //$contentStorageInfo = ProductSlaveContentStorageModel::select(DB::raw('SUM(num) as total_num'))->where($slaveCondition)->first()->toArray();

            //echo $contentInfo['num'].'=========='.($contentStorageInfo['total_num']-$val['num']);die;
            /* if(($contentStorageInfo['total_num']-$val['num']) < $contentInfo['num']){
                throw new Exception('单个原料的总库存和还库的数量差，不能小于生产订单原料数量！');
            } */
            $leftBalanceNum = $contentInfo['num']-$contentInfo['actual_num'];//总可还库数量
            $leftHandleNum = $leftBalanceNum - $contentInfo['handle_num'];//剩余可还库数量

            if($leftBalanceNum >= ($contentInfo['handle_num'] + $val['num'])){
                ProductSlaveContentModel::where($slaveCondition)->increment('handle_num',$val['num']);
            }else{
                throw new Exception('商品:'.$materielTypeInfo['materiel_name'].'还库数量不能超出最低要求数量:'.$contentInfo['actual_num'].',已超出:'.(($contentInfo['handle_num'] + $val['num']) - $leftBalanceNum));
            }

            if(!empty($val['serial_info'])) {
                foreach($val['serial_info'] as $serialVal) {
                    $content[] = [
                        'product_order_id' => $data['id'],
                        'union_code' => $unionCode,
                        'type' => 1,
                        'type_id' => $val['type_id'],
                        'storage_manage_id' => $serialVal['storage_manage_id'],
                        'serial_id' => $serialVal['serial_id'],
                        'num' => $serialVal['num'],
                        'created_at' => time()
                    ];
                }
            }else {

                foreach($val['storage_manage_info'] as $storageVal) {
                    $content[] = [
                        'product_order_id' => $data['id'],
                        'union_code' => $unionCode,
                        'type_id' => $val['type_id'],
                        'type' => 1,
                        'storage_manage_id' => $storageVal['storage_manage_id'],
                        'serial_id' => 0,
                        'num' => $storageVal['num'],
                        'created_at' => time()
                    ];
                }
            }

           /*  $list = ProductSlaveContentStorageModel::select('id','num')
                    ->where($slaveCondition)->where('num','>','0')->orderBy('num','desc')->get()->toArray();
            $num = $val['num'];//这个是还库数量 10
            foreach($list as $sKey => $sVal){//查询的商品多库存数量
                //10-11=-1;10-10=0;10-9=1;
                $num = $num - $sVal['num'];
               if(($num == 0 && $sKey == 0) || ($num < 0 && $sKey == 0)){//第一个次循环，正好商品多库存数量够扣还库数量
                  ProductSlaveContentStorageModel::where('id',$sVal['id'])->decrement('num', $val['num']);
                  break;
               }elseif (($num == 0 && $sKey > 0) || ($num < 0 && $sKey > 0)){//N次循环，正好商品多库存数量够扣还库数量
                   ProductSlaveContentStorageModel::where('id',$sVal['id'])->decrement('num', $num + $sVal['num']);
                   break;
               }elseif($num > 0){//还库数量大于商品每个库存数量，一直循环扣
                   ProductSlaveContentStorageModel::where('id',$sVal['id'])->decrement('num', $sVal['num']);
               }
            } */
        }

        //ProductFillOrBalanceModel::insert($task);
//        ProductFillOrBalanceContentModel::insert($content);
        foreach($content as $fillContent) {
            $getFillInfo = ProductFillOrBalanceContentModel::where([
                'product_order_id' => $fillContent['product_order_id'],
                'type_id' => $fillContent['type_id'],
                'serial_id' => $fillContent['serial_id'],
                'type' => 1
            ])->first();

            if(empty($getFillInfo)) {
                ProductFillOrBalanceContentModel::insert($fillContent);
            }
            else {
                $getFillInfo->num = $getFillInfo->num + $fillContent['num'];
                $getFillInfo->save();
            }
        }

        $storageManageData = [];
        $serialId = [];
        $logData = [];
        foreach($content as $vals) {
            if($vals['serial_id'] != 0) {
                $serialInfo = SerialNumberModel::where('id', $vals['serial_id'])->first();

                if($serialInfo['status']) {
                    throw new Exception('序列号:'.$serialInfo['serial_no'].'未被使用，无法用于还库');
                }

                $serialId[] = [
                    'id' => $vals['serial_id'],
                    'status' => 1
                ];

                $serialNo = $serialInfo['serial_no'];
            }

            $arr['id'] = $vals['storage_manage_id'];

            $storageManageInfo = StorageManageModel::detail($arr);

//            $storageManageData[] = [
//                'id' => $vals['storage_manage_id'],
//                'in_storage_num' => $storageManageInfo['in_storage_num'] + $vals['num'],
//                'virtual_storage_num' => $storageManageInfo['virtual_storage_num'] + $vals['num'],
//                'delete_flag' => 0
//            ];

            ProductSlaveContentStorageModel::where([
                'product_order_id' => $data['id'],
                'storage_manage_id' => $vals['storage_manage_id'],
                'serial_id' => $vals['serial_id'],
                'type_id' => $vals['type_id']
            ])
                ->lockForUpdate()
                ->increment('handle_num', $vals['num']);

            $serialNo = '';

            $logData[] = self::inStorageLog($data, $vals['num'], $storageManageInfo, $serialNo, 4, $unionCode, '', 3);
            $storageManageInfo->in_storage_num = $storageManageInfo->in_storage_num + $vals['num'];
            $storageManageInfo->virtual_storage_num = $storageManageInfo->virtual_storage_num + $vals['num'];
            $storageManageInfo->save();
        }

        //序列号入库-更新已使用序列号状态
        if(!empty($serialId)) {
            batch()->update(new SerialNumberModel, $serialId, 'id');
        }

        //扣除库存
        if(!empty($storageManageData)) {
            batch()->update(new StorageManageModel, $storageManageData, 'id');
        }

        if(!empty($logData)) {
            LogInStorageModel::insert($logData);
        }

        CommonService::cancelAlertFlag($data['main_id']);

        return true;
    }
    private static function outStorageLog2(array $data, $num, $storageManageInfo, string $serialNo, $allIdType, $unionCode = '', $remark = '')
    {
        $logData = [
            'type' => 0,
            'curr_storage_manage_id' => $storageManageInfo['id'],
            'storage_id' => $storageManageInfo['storage_id'],
            'storage_name' => $storageManageInfo['storage_name'],
            'storage_address' => $storageManageInfo['storage_address'],
            'materiel_class_id' => $storageManageInfo['s_class_id'],
            'materiel_class_name' => $storageManageInfo['s_class_name'],
            'materiel_class_no' => $storageManageInfo['s_class_no'],
            'materiel_type_id' => $storageManageInfo['type_id'],
            'materiel_name' => $storageManageInfo['materiel_name'],
            'type_name' => $storageManageInfo['type_name'],
            'materiel_no' => $storageManageInfo['materiel_no'],
            /* 'purchase_no' => $unionCode, */
            'operate_num' => $num,
            'last_storage_num' => $storageManageInfo['in_storage_num'],
            'next_storage_num' => $storageManageInfo['in_storage_num'] + $num,
            'materiel_mean_cost' => $storageManageInfo['materiel_mean_cost'],
            'serial_number' => $serialNo,
            'all_id_type' => $allIdType,
            'all_id' => $data['id'],
            'user_id' => $data['user_id'],
            'main_id' => $data['main_id'],
            /* 'in_storage_time' => time(), */
            'created_at' => time(),
            'remark' => empty($remark)?'':$remark,
            'shelf_id' => $storageManageInfo['shelf_id'],
            'location_id' => $storageManageInfo['location_id'],
        ];

           MessageService::sendInSms(
         '',
         $storageManageInfo['materiel_name'],
         $storageManageInfo['type_name'],
         $storageManageInfo['storage_id'],
         $storageManageInfo['storage_name'],
         $data['user_id'],
         $num,
         $storageManageInfo['in_storage_num'] + $num
         );

        return $logData;
    }

    public static function productReturnStorageSerialSelect(array $all)
    {
        $keyword = empty($all['keyword'])?'':$all['keyword'];
        $serialId = [];
        if(!empty($all['product_serial_id'])) {
            $serialId = array_filter(explode(',',$all['product_serial_id']), function($v) { return $v !== ''; });
        }

        $serialInfo = SerialNumberModel::select(
            'a.goods_id as type_id',
            'materiel_name',
            'type_name',
            'a.serial_no',
            'a.id',
            'a.storage_manage_id',
            'package_id'
        )
            ->where([
                'package_storage_id' => $all['id'],
            ])
            ->from('serial_number as a')
            ->leftJoin('materiel_type as b', 'b.id', '=', 'a.goods_id')
//            ->leftJoin('materiel_product_content as c', 'c.type_id', '=', 'b.id')
            ->where('a.status',1)
            ->where('a.storage_manage_id', '!=', $all['id'])
            ->where(function($query) use($keyword) {
                $query->where('materiel_name', 'like', '%'.$keyword.'%')
                    ->orWhere('serial_no', 'like', '%'.$keyword.'%')
                    ->orWhere('type_name', 'like', '%'.$keyword.'%')
                    ->orWhere('materiel_no', 'like', '%'.$keyword.'%');
            });
        if(!empty($serialId)) {
            $serialInfo->whereIn('a.parent_id', $serialId);
        }
        $serialInfo = $serialInfo->get()->toArray();


        $arr = [];

        if(!empty($serialInfo)) {
            foreach($serialInfo as $key => $value) {
                $materialTypePackageContentInfo = MaterielProductContentModel::where([
                    'product_id' => $value['package_id'],
                    'type_id' => $value['type_id']
                ])
                    ->first();

                $arr[$value['type_id']]['type_id'] = $value['type_id'];
                $arr[$value['type_id']]['materiel_name'] = $value['materiel_name'];
                $arr[$value['type_id']]['type_name'] = $value['type_name'];
                $arr[$value['type_id']]['num'] = $materialTypePackageContentInfo['num'];
                $arr[$value['type_id']]['serial_info'][] = [
                    'serial_id' => $value['id'],
                    'serial_no' => $value['serial_no'],
                    'storage_manage_id' => $value['storage_manage_id'],
                ];
            }
        }

        return array_values($arr);
    }


    public static function productReturnStorageSerialSelect1(array $all)
    {
        $keyword = empty($all['keyword'])?'':$all['keyword'];

        $serialInfo = SerialNumberModel::select(
            'a.goods_id as type_id',
            'materiel_name',
            'type_name',
//            'product_id',
//            'c.num',
            'a.serial_no',
            'a.id',
            'a.storage_manage_id',
            'package_id'
        )
            ->where([
                'package_storage_id' => $all['id'],
            ])
            ->from('serial_number as a')
            ->leftJoin('materiel_type as b', 'b.id', '=', 'a.goods_id')
//            ->leftJoin('materiel_product_content as c', 'c.type_id', '=', 'b.id')
            ->where('a.status',1)
            ->where(function($query) use($keyword) {
                $query->where('materiel_name', 'like', '%'.$keyword.'%')
                    ->orWhere('serial_no', 'like', '%'.$keyword.'%')
                    ->orWhere('type_name', 'like', '%'.$keyword.'%')
                    ->orWhere('materiel_no', 'like', '%'.$keyword.'%');
            })
            ->get()->toArray();

        $arr = [];
        foreach($serialInfo as $key => $value) {
            $materialTypePackageContentInfo = MaterielProductContentModel::where([
                'product_id' => $value['package_id'],
                'type_id' => $value['type_id']
            ])
                ->first();
            $arr[$value['type_id']]['type_id'] = $value['type_id'];
            $arr[$value['type_id']]['materiel_name'] = $value['materiel_name'];
            $arr[$value['type_id']]['type_name'] = $value['type_name'];
            $arr[$value['type_id']]['num'] = $materialTypePackageContentInfo['num'];
            $arr[$value['type_id']]['serial_info'][] = [
                'serial_id' => $value['id'],
                'serial_no' => $value['serial_no'],
                'storage_manage_id' => $value['storage_manage_id'],
            ];
        }

        return array_values($arr);
    }




    private static function inStorageLog(array $data, $num, $storageManageInfo, string $serialNo, $allIdType, $unionCode = '', $remark = '', $type = 0)
    {
        $logData = [
            'type' => $type,
            'curr_storage_manage_id' => $storageManageInfo['id'],
            'storage_id' => $storageManageInfo['storage_id'],
            'storage_name' => $storageManageInfo['storage_name'],
            'storage_address' => $storageManageInfo['storage_address'],
            'materiel_class_id' => $storageManageInfo['s_class_id'],
            'materiel_class_name' => $storageManageInfo['s_class_name'],
            'materiel_class_no' => $storageManageInfo['s_class_no'],
            'materiel_type_id' => $storageManageInfo['type_id'],
            'materiel_name' => $storageManageInfo['materiel_name'],
            'type_name' => $storageManageInfo['type_name'],
            'materiel_no' => $storageManageInfo['materiel_no'],
            'purchase_no' => $unionCode,
            'operate_num' => $num,
            'last_storage_num' => $storageManageInfo['in_storage_num'],
            'next_storage_num' => $storageManageInfo['in_storage_num'] + $num,
            'materiel_mean_cost' => $storageManageInfo['materiel_mean_cost'],
            'serial_number' => $serialNo,
            'all_id_type' => $allIdType,
            'all_id' => $data['id'],
            'user_id' => $data['user_id'],
            'main_id' => $data['main_id'],
            'in_storage_time' => time(),
            'created_at' => time(),
            'remark' => empty($remark)?'':$remark,
            'shelf_id' => $storageManageInfo['shelf_id'],
            'location_id' => $storageManageInfo['location_id'],
        ];

        MessageService::sendInSms(
            '',
            $storageManageInfo['materiel_name'],
            $storageManageInfo['type_name'],
            $storageManageInfo['storage_id'],
            $storageManageInfo['storage_name'],
            $data['user_id'],
            $num,
            $storageManageInfo['in_storage_num'] + $num
        );

        return $logData;
    }

    //生产订单出入库
    public static function inOrOut(array $data, $time)
    {
        $productInfo = ProductOrderModel::getMainOrderInfo($data['id'], $data['main_id']);

        if($productInfo['product_status'] != 2) {
            return ['code' => 1, 'msg' => '生产订单已完成后才可以出入库或套件返仓', 'data' => ''];
        }

        //验证每次入库是否与初次入库类型相符，初次入库后，固定后续每次入库的操作方式
        if($productInfo['in_storage_type'] != 0) {
//            if(in_array($data['type'], [0,1])) {
                if($productInfo['in_storage_type'] != $data['type']) {
                    return ['code' => 1, 'msg' => '当前入库类型与初次入库类型不符', 'data' => ''];
//                }
            }
        }

        if($productInfo['storage_operate_status'] == 2) {
            return ['code' => 1, 'msg' => '当前单据的出入库操作已完成，无法再次操作', 'data' => ''];
        }

        DB::beginTransaction();

        try {
            switch($data['type']) {
                case 1://整件入库
                    self::fullInStorage($data, $productInfo, $time);
                    break;
//                case 2://套件返仓
//                    self::piecesInStorage($data, $productInfo);
//                    break;
                case 3://出库
                    self::productOutStorage($data, $productInfo, $time);
                    break;
            }
            
            CommonService::setAlertFlag($data['main_id']);
            CommonService::cancelAlertFlag($data['main_id']);

            DB::commit();

            if(in_array($data['type'], [1,3])) {
                $checkSlave = ProductSlaveModel::where('product_order_id', $data['id'])
                    ->whereRaw('num > storage_operate_num')
                    ->first();

                $status = 1;
                if(!empty($checkSlave)) {
                    $status = 1;
                }
                else {
                    $status = 2;
                }

                //同步销售单状态
                if($data['type'] == 3) {
                    SellModel::where('id', $productInfo['product_source_id'])->update(['out_status' => $status]);
                }

                $productInfo->storage_operate_status = $status;
                $productInfo->save();
            }
            else if($data['type'] == 1) {
                $checkSlave = ProductSlaveContentModel::where('product_order_id', $data['id'])
                    ->whereRaw('num > storage_operate_num')
                    ->first();

                if(!empty($checkSlave)) {
                    $productInfo->storage_operate_status = 1;
                }
                else {
                    $productInfo->storage_operate_status = 2;
                }

                $productInfo->save();
            }
            return ['code' => 0, 'msg' => 'success', 'data' => ''];
        }
        catch(Exception $e) {
            Log::debug('生产订单出入库异常'.var_export($e->getMessage(), true));
            DB::rollBack();
            return ['code' => 1, 'msg' => $e->getMessage(), 'data' => ''];
        }
    }

    //整件入库
    private static function fullInStorage(array $data, $productInfo, $time)
    {
        if(empty($data['task_content'])) {
            throw new Exception('请选择要入库的生产任务');
        }

        $storageInfo = StorageModel::where([
            'id' => $data['storage_id'],
            'main_id' => $data['main_id'],
            'delete_flag' => 0
        ])->first();

        if(!isset($data['location_id'])) {
            $shelfInfo = StorageShelfModel::where('storage_id', $data['storage_id'])->where('shelf_type', 1)->first();
            $locationInfo = StorageShelfLocationModel::where([
                'shelf_id' => $shelfInfo['id'],
                'location_type' => 1
            ])->first();

            $shelfId = $shelfInfo['id'];
            $locationId = $locationInfo['id'];
        }
        else {
            $shelfId = $data['shelf_id'];
            $locationId = $data['location_id'];
        }

        $taskContent = json_decode($data['task_content'], true);

        if(!is_array($taskContent) || empty($taskContent)) {
            throw new Exception('无效生产任务，请重试');
        }

        $slaveData = [];//要入库的任务数
        $logData = [];//入库记录
        $existStorageData = [];//已存在的商品库存信息
        $storageSerialData = [];//库存序列号数据信息
        $productSerialData = [];//生产订单序列号数据信息
        $materielContentData = [];//未使用序列号的套餐内商品信息

        foreach($taskContent as $value) {
            if($value['num'] == 0) {
                throw new Exception('入库数量不能为0');
            }

            $slaveInfo = ProductSlaveModel::where('id', $value['id'])->first();

            if ($value['num'] > ($slaveInfo['num'] - $slaveInfo['storage_operate_num'])) {
                throw new Exception('超出可入库数量,当前可入库数量为' . ($slaveInfo['num'] - $slaveInfo['storage_operate_num']));
            }

            $slaveData[] = [
                'id' => $value['id'],
                'storage_operate_num' => $slaveInfo['storage_operate_num'] + $value['num'],
            ];

            $materielTypeInfo = MaterielTypeModel::getMainInfo($value['type_id']);

            $productUseTag = $materielTypeInfo['is_product_materiel']?1:0;

            MaterielTypeModel::where('id', $materielTypeInfo['id'])
                ->update([
                    'product_use_tag' => $productUseTag
                ]);

            //检查库存中是否存在
            $checkStorageManageInfo = StorageManageModel::getInfos([
                'type_id' => $value['type_id'],
                'storage_id' => $data['storage_id'],
                'main_id' => $data['main_id'],
//                'shelf_id' => $shelfId,
//                'location_id' => $locationId
            ]);

            if($value['is_use_serial'] && empty($value['serial_info'])) {
                throw new Exception('商品:'.$materielTypeInfo['materiel_name'].'已开启序列号');
            }

            //开始库存处理
            //库存信息是否已存在，存在则更新库存数，不存在则新增库存信息
            if(empty($checkStorageManageInfo)) {
                $storageManageId = StorageManageModel::insertGetId([
                    'materiel_class_id' => $materielTypeInfo['materiel_class_id'],
                    'materiel_class_name' => $materielTypeInfo['sec_class_name'],
                    'materiel_class_no' => $materielTypeInfo['sec_class_no'],
                    'type_id' => $materielTypeInfo['id'],
                    'materiel_name' => $materielTypeInfo['materiel_name'],
                    'type_name' => $materielTypeInfo['type_name'],
                    'materiel_no' => $materielTypeInfo['materiel_no'],
                    'materiel_mean_cost' => $materielTypeInfo['cost'],
                    'storage_id' => $data['storage_id'],
                    'storage_name' => $storageInfo['storage_name'],
                    'storage_address' => $storageInfo['storage_address'],
                    'in_storage_num' => $value['num'],
                    'virtual_storage_num' => $value['num'],
                    'main_id' => $data['main_id'],
                    'in_storage_time' => $data['in_storage_time'],
                    'is_product_materiel' => $materielTypeInfo['is_product_materiel'],
                    'created_at' => $time,
                    'shelf_id' => $shelfId,
                    'location_id' => $locationId
                ]);

                $lastStorageNum = 0;
                $nextStorageNum = $value['num'];
            }
            else {
                $lastStorageNum = $checkStorageManageInfo['in_storage_num'];
                $nextStorageNum = $checkStorageManageInfo['in_storage_num'] + $value['num'];
                $storageManageId = $checkStorageManageInfo['id'];

                $existStorageData[] = [
                    'id' => $checkStorageManageInfo['id'],
                    'virtual_storage_num' => $checkStorageManageInfo['virtual_storage_num'] + $value['num'],
                    'in_storage_num' => $nextStorageNum,
                    'delete_flag' => 0
                ];
            }

//            MessageService::sendInSms(
//                '',
//                $materielTypeInfo['materiel_name'],
//                $materielTypeInfo['type_name'],
//                $data['storage_id'],
//                $storageInfo['storage_name'],
//                $data['user_id'],
//                $value['num'],
//                $nextStorageNum,
//            );

            //结束库存处理

            $serialNumberStr = '';
            $serialIdInfo = [];
            //开始对序列号处理
            if(!empty($value['serial_info'])) {
                if(!is_integer($value['num'])) {
                    throw new Exception('商品:'.$materielTypeInfo['materiel_name'].'-'.
                        $materielTypeInfo['type_name'].'已开启序列号,序列号数量仅能为整数');
                }
                if($value['is_product_materiel']) {
                    foreach($value['serial_info'] as $serialInfoValue) {
                        $checkProductSerialInfo = SerialNumberModel::where([
                            'goods_id' => $value['type_id'],
                            'serial_no' => $serialInfoValue['serial_no']
                        ])->first();

                        if(!empty($checkProductSerialInfo)) {
                            throw new Exception('套餐:'.$materielTypeInfo['materiel_name'].'中序列号:'.$serialInfoValue['serial_no'].'已存在');
                        }

                        $productSerialId = SerialNumberModel::insertGetId([
                            'main_id' => $data['main_id'],
                            'serial_no' => $serialInfoValue['serial_no'],
                            'goods_id' => $value['type_id'],
                            'storage_manage_id' => $storageManageId,
                            'parent_id' => 0,
                            'status' => 1
                        ]);

                        $productSerialInfo = array_filter(explode(',', $serialInfoValue['serial_content']));

                        $getSerialInfo = ProductSlaveContentStorageModel::select(
                            'a.id',
                            'serial_id',
                            'a.type_id',
                            'b.serial_no'
                        )
                            ->from('product_slave_content_storage as a')
                            ->leftJoin('serial_number as b', 'b.id', '=', 'a.serial_id')
                            ->where('product_order_id', $data['id'])
                            ->whereIn('b.id', $productSerialInfo)
                            ->get()->toArray();

                        foreach($getSerialInfo as $productVal) {
                            $serialNumberStr .= $productVal['serial_no'].',';

                            //是否为套餐
                            if($value['is_product_materiel']) {
                                //库存序列号更新
                                $storageSerialData[] = [
                                    'id' => $productVal['serial_id'],
                                    'parent_id' => $productSerialId,
                                    'package_id' => $value['type_id'],
                                    'package_storage_id' => $storageManageId,
                                    'status' => 1
                                ];
                            }
                            else {
                                //库存序列号更新
                                $storageSerialData[] = [
                                    'id' => $productVal['serial_id'],
                                    'package_id' => 0,
                                    'package_storage_id' => $storageManageId,
                                    'status' => 1
                                ];
                            }

                            //生产订单序列号更新
                            $productSerialData[] = [
                                'id' => $productVal['id'],
                                'flag' => 2,
                                'storage_operate_num' => 1
                            ];
                        }
                    }
                }
                else {
                    $serialInfo = array_filter(explode(',', $value['serial_info']));

                    $getSerialInfo = ProductSlaveContentStorageModel::select(
                        'a.id',
                        'serial_id',
                        'a.type_id',
                        'b.serial_no'
                    )
                        ->from('product_slave_content_storage as a')
                        ->leftJoin('serial_number as b', 'b.id', '=', 'a.serial_id')
                        ->where('product_order_id', $data['id'])
                        ->whereIn('b.id', $serialInfo)
                        ->get()->toArray();

                    foreach($getSerialInfo as $val) {
                        $serialNumberStr .= $val['serial_no'].',';
                        $pInfo=MaterielProductContentModel::where('type_id',$val['type_id'])->first();
                        //是否为套餐
                        if($value['is_product_materiel']) {
                            //库存序列号更新
                            $storageSerialData[] = [
                                'id' => $val['serial_id'],
                                'package_id' => $value['type_id'],
                                'package_storage_id' => $storageManageId,
                                'status' => 1
                            ];
                        }
                        else {
                            //库存序列号更新
                            $storageSerialData[] = [
                                'id' => $val['serial_id'],
                                'package_id' => 0,
                                'storage_manage_id' => $storageManageId,
                                'package_storage_id' => 0,
                                'status' => 1
                            ];
                        }

                        //生产订单序列号更新
                        $productSerialData[] = [
                            'id' => $val['id'],
                            'flag' => 2,
                            'storage_operate_num' => 1
                        ];

                        //获取生产入库所需序列号id
                        $serialIdInfo[] = $val['serial_id'];
                    }
                }
            }
            //结束对序列号处理

            $serialNumberInfo = implode(',',array_unique(explode(',', substr($serialNumberStr, 0, -1))));

            $logData[] = [
                'type' => 0,
                'curr_storage_manage_id' => $storageManageId,
                'storage_id' => $data['storage_id'],
                'storage_name' => $storageInfo['storage_name'],
                'storage_address' => $storageInfo['storage_address'],
                'materiel_class_id' => $materielTypeInfo['materiel_class_id'],
                'materiel_class_name' => $materielTypeInfo['sec_class_name'],
                'materiel_class_no' => $materielTypeInfo['sec_class_no'],
                'materiel_type_id' => $materielTypeInfo['id'],
                'materiel_name' => $materielTypeInfo['materiel_name'],
                'type_name' => $materielTypeInfo['type_name'],
                'materiel_no' => $materielTypeInfo['materiel_no'],
                'purchase_no' => $productInfo['product_no'],
                'operate_num' => $value['num'],
                'last_storage_num' => $lastStorageNum,
                'next_storage_num' => $nextStorageNum,
                'materiel_mean_cost' => $materielTypeInfo['cost'],
                'serial_number' => $serialNumberInfo,
                'all_id_type' => 4,
                'all_id' => $data['id'],
                'user_id' => $data['user_id'],
                'main_id' => $data['main_id'],
                'in_storage_time' => $data['in_storage_time'],
                'created_at' => $time,
                'shelf_id' => $shelfId,
                'remark' => empty($value['remark'])?'':$value['remark'],
                'label_id' => $data['label_id'],
                'label_name' => $data['label_name'],
                'location_id' => $locationId
            ];

            //开始对任务为套餐的情况进行处理
            if($value['is_product_materiel']) {
                //获取套餐内商品信息
                $materielProductContentInfo = MaterielProductContentModel::where([
                    'product_id' => $value['type_id'],
                ])
                    ->get()->toArray();

                foreach($materielProductContentInfo as $v) {
                    if(isset($materielContentData[$v['type_id']])) {
                        $materielContentData[$v['type_id']]['num'] += $v['num'] * $value['num'];
                    }
                    else {
                        $materielContentData[$v['type_id']] = [
                            'type_id' => $v['type_id'],
                            'num' => $v['num'] * $value['num'],
                        ];
                    }
                }
            }
            else {
                if(isset($materielContentData[$value['type_id']])) {
                    $materielContentData[$value['type_id']]['num'] += $value['num'];
                }
                else {
                    $materielContentData[$value['type_id']] = [
                        'type_id' => $value['type_id'],
                        'num' => $value['num'],
                    ];
                }
            }
            //结束对任务为套餐的情况进行处理
        }

        if(!empty($materielContentData)) {
            $updateOperateData = [];
            $discountContentData = [];//扣除原料表中对应的原料信息
            foreach($materielContentData as $v1) {
                $getSlaveContentInfo = ProductSlaveContentModel::where([
                    'product_order_id' => $data['id'],
                    'type_id' => $v1['type_id'],
                ])
                    ->first();

                $discountContentData[] = [
                    'id' => $getSlaveContentInfo['id'],
                    'storage_operate_num' => $getSlaveContentInfo['storage_operate_num'] + $v1['num'],
                ];

                //查找到未全部入库的所有
                $slaveContentStorage = ProductSlaveContentStorageModel::where([
                    'type_id' => $v1['type_id'],
                    'product_order_id' => $data['id'],
                ])
                    ->whereRaw('num != storage_operate_num')
                    ->orderBy('storage_operate_num', 'asc')
                    ->get()->toArray();


                if(empty($slaveContentStorage)) {
                    throw new Exception('原料已无可入库内容，请重试');
                }

                $tempNum = $getSlaveContentInfo['storage_operate_num'] + $v1['num'];//实际消耗数量 11

                //递归扣除所需的库存数量
                foreach($slaveContentStorage as $val) {
                    $nowLeftNum = $val['num'] - $val['storage_operate_num'];//当前剩余可操作数量

                    if($tempNum <= $nowLeftNum || ($tempNum - $nowLeftNum == 0)) {
                        $updateOperateData[] = [
                            'id' => $val['id'],
                            'storage_operate_num' => $val['storage_operate_num'] + $tempNum
                        ];
                        break;
                    }
                    else {
                        $tempNum -= $nowLeftNum;//剩余可操作 5

                        if($tempNum > 0) {
                            $updateOperateData[] = [
                                'id' => $val['id'],
                                'storage_operate_num' => $val['storage_operate_num'] + $nowLeftNum
                            ];
                        }
                        else {
                            $updateOperateData[] = [
                                'id' => $val['id'],
                                'storage_operate_num' => $val['storage_operate_num'] + $tempNum
                            ];
                        }
                    }

                }
            }

            if(!empty($discountContentData)) {
                batch()->update(new ProductSlaveContentModel, $discountContentData, 'id');
            }

            if(!empty($updateOperateData)) {
                batch()->update(new ProductSlaveContentStorageModel, $updateOperateData, 'id');
            }
        }

        if(!empty($logData)) {
            LogInStorageModel::insert($logData);
        }

        if(!empty($slaveData)) {
            batch()->update(new ProductSlaveModel, $slaveData, 'id');
        }

        if(!empty($existStorageData)) {
            batch()->update(new StorageManageModel, $existStorageData, 'id');
        }

        if(!empty($productSerialData)) {
            batch()->update(new ProductSlaveContentStorageModel, $productSerialData, 'id');
        }

        if(!empty($storageSerialData)) {
            batch()->update(new SerialNumberModel, $storageSerialData, 'id');
        }

        return true;
    }

    private static function fullInStorage2(array $data, $productInfo)
    {
        if(empty($data['task_content'])) {
            throw new Exception('请选择要入库的生产任务');
        }

        $storageInfo = StorageModel::where([
            'id' => $data['storage_id'],
            'main_id' => $data['main_id'],
            'delete_flag' => 0
        ])->first();

//        if(empty($storageInfo)) {
//            throw new Exception('仓库不存在');
//        }

        if($data['use_shelf']) {
            if($data['location_id'] == 0) {
                throw new Exception('设置中已开启货架，请选择货架库位后重试');
            }

            $shelfId = $data['shelf_id'];
            $locationId = $data['location_id'];
        }
        else {
            $shelfInfo = StorageShelfModel::where('storage_id', $data['storage_id'])->where('shelf_type', 1)->first();
            $locationInfo = StorageShelfLocationModel::where([
                'shelf_id' => $shelfInfo['id'],
                'location_type' => 1
            ])->first();

            $shelfId = $shelfInfo['id'];
            $locationId = $locationInfo['id'];
        }

        $taskContent = json_decode($data['task_content'], true);

        $slaveData = [];//要入库的任务数
        $logData = [];//入库记录
        $existStorageData = [];//已存在的商品库存信息
        $storageSerialData = [];//库存序列号数据信息
        $productSerialData = [];//生产订单序列号数据信息
        $materielContentData = [];//未使用序列号的套餐内商品信息
        foreach($taskContent as $value) {
            if($value['num'] == 0) {
                throw new Exception('入库数量不能为0');
            }

            $slaveInfo = ProductSlaveModel::where('id', $value['id'])->first();

            if ($value['num'] > ($slaveInfo['num'] - $slaveInfo['storage_operate_num'])) {
                throw new Exception('超出可入库数量,当前可入库数量为' . ($slaveInfo['num'] - $slaveInfo['storage_operate_num']));
            }

            $slaveData[] = [
                'id' => $value['id'],
                'storage_operate_num' => $slaveInfo['storage_operate_num'] + $value['num'],
            ];

            $materielTypeInfo = MaterielTypeModel::getMainInfo($value['type_id']);

            //检查库存中是否存在
            $checkStorageManageInfo = StorageManageModel::getInfos([
                'type_id' => $value['type_id'],
                'storage_id' => $data['storage_id'],
                'main_id' => $data['main_id'],
                'shelf_id' => $shelfId,
                'location_id' => $locationId
            ]);

            //开始库存处理
            //库存信息是否已存在，存在则更新库存数，不存在则新增库存信息
            if(empty($checkStorageManageInfo)) {
                $storageManageId = StorageManageModel::insertGetId([
                    'materiel_class_id' => $materielTypeInfo['materiel_class_id'],
                    'materiel_class_name' => $materielTypeInfo['sec_class_name'],
                    'materiel_class_no' => $materielTypeInfo['sec_class_no'],
                    'type_id' => $materielTypeInfo['id'],
                    'materiel_name' => $materielTypeInfo['materiel_name'],
                    'type_name' => $materielTypeInfo['type_name'],
                    'materiel_no' => $materielTypeInfo['materiel_no'],
                    'materiel_mean_cost' => $materielTypeInfo['cost'],
                    'storage_id' => $data['storage_id'],
                    'storage_name' => $storageInfo['storage_name'],
                    'storage_address' => $storageInfo['storage_address'],
                    'in_storage_num' => $value['num'],
                    'virtual_storage_num' => $value['num'],
                    'main_id' => $data['main_id'],
                    'in_storage_time' => time(),
                    'is_product_materiel' => $materielTypeInfo['is_product_materiel'],
                    'created_at' => time(),
                    'shelf_id' => $shelfId,
                    'location_id' => $locationId
                ]);

                $lastStorageNum = 0;
                $nextStorageNum = $value['num'];
            }
            else {
                $lastStorageNum = $checkStorageManageInfo['in_storage_num'];
                $nextStorageNum = $checkStorageManageInfo['in_storage_num'] + $value['num'];
                $storageManageId = $checkStorageManageInfo['id'];

                $existStorageData[] = [
                    'id' => $checkStorageManageInfo['id'],
                    'virtual_storage_num' => $checkStorageManageInfo['virtual_storage_num'] + $value['num'],
                    'in_storage_num' => $nextStorageNum,
                    'delete_flag' => 0
                ];
            }
//
//            MessageService::sendInSms(
//                '',
//                $materielTypeInfo['materiel_name'],
//                $materielTypeInfo['type_name'],
//                $data['storage_id'],
//                $storageInfo['storage_name'],
//                $data['user_id'],
//                $value['num'],
//                $nextStorageNum,
//            );

            //结束库存处理

            $serialNumberStr = '';
            $serialIdInfo = [];
            //开始对序列号处理
            if(!empty($value['serial_info'])) {
                $serialInfo = array_filter(explode(',', $value['serial_info']));

                $getSerialInfo = ProductSlaveContentStorageModel::select(
                    'a.id',
                    'serial_id',
                    'a.type_id',
                    'b.serial_no'
                )
                    ->from('product_slave_content_storage as a')
                    ->leftJoin('serial_number as b', 'b.id', '=', 'a.serial_id')
                    ->whereIn('b.id', $serialInfo)
                    ->get()->toArray();

                foreach($getSerialInfo as $val) {
                    $serialNumberStr .= $val['serial_no'].',';
                    $pInfo=MaterielProductContentModel::where('type_id',$val['type_id'])->first();
                    //是否为套餐
                    if($value['is_product_materiel']) {
                        //库存序列号更新
                        $storageSerialData[] = [
                            'id' => $val['serial_id'],
                            'package_id' => $value['type_id'],
                            'package_storage_id' => $storageManageId,
                            'status' => 1
                        ];
                    }
                    else {
                        //库存序列号更新
                        $storageSerialData[] = [
                            'id' => $val['serial_id'],
                            'package_id' => 0,
                            'storage_manage_id' => $storageManageId,
                            'package_storage_id' => 0,
                            'status' => 1
                        ];
                    }


                    //生产订单序列号更新
                    $productSerialData[] = [
                        'id' => $val['id'],
                        'storage_operate_num' => 1
                    ];

                    //获取生产入库所需序列号id
                    $serialIdInfo[] = $val['serial_id'];
                }
            }
            //结束对序列号处理

            $serialNumberInfo = implode(',',array_unique(explode(',', substr($serialNumberStr, 0, -1))));

            $logData[] = [
                'type' => 0,
                'curr_storage_manage_id' => $storageManageId,
                'storage_id' => $data['storage_id'],
                'storage_name' => $storageInfo['storage_name'],
                'storage_address' => $storageInfo['storage_address'],
                'materiel_class_id' => $materielTypeInfo['materiel_class_id'],
                'materiel_class_name' => $materielTypeInfo['sec_class_name'],
                'materiel_class_no' => $materielTypeInfo['sec_class_no'],
                'materiel_type_id' => $materielTypeInfo['id'],
                'materiel_name' => $materielTypeInfo['materiel_name'],
                'type_name' => $materielTypeInfo['type_name'],
                'materiel_no' => $materielTypeInfo['materiel_no'],
                'purchase_no' => $productInfo['product_no'],
                'operate_num' => $value['num'],
                'last_storage_num' => $lastStorageNum,
                'next_storage_num' => $nextStorageNum,
                'materiel_mean_cost' => $materielTypeInfo['cost'],
                'serial_number' => $serialNumberInfo,
                'all_id_type' => 4,
                'all_id' => $data['id'],
                'user_id' => $data['user_id'],
                'main_id' => $data['main_id'],
                'in_storage_time' => time(),
                'created_at' => time(),
                'shelf_id' => $shelfId,
                'remark' => empty($value['remark'])?'':$value['remark'],
                'location_id' => $locationId
            ];

            //开始对任务为套餐的情况进行处理
            if($value['is_product_materiel']) {
                //获取套餐内商品信息
                $materielProductContentInfo = MaterielProductContentModel::where([
                    'product_id' => $value['type_id'],
                ])
                    ->get()->toArray();

                foreach($materielProductContentInfo as $v) {
                    if(isset($materielContentData[$v['type_id']])) {
                        $materielContentData[$v['type_id']]['num'] += $v['num'] * $value['num'];
                    }
                    else {
                        $materielContentData[$v['type_id']] = [
                            'type_id' => $v['type_id'],
                            'num' => $v['num'] * $value['num'],
                        ];
                    }
                }
            }
            else {
                if(isset($materielContentData[$value['type_id']])) {
                    $materielContentData[$value['type_id']]['num'] += $value['num'];
                }
                else {
                    $materielContentData[$value['type_id']] = [
                        'type_id' => $value['type_id'],
                        'num' => $value['num'],
                    ];
                }
            }
            //结束对任务为套餐的情况进行处理
        }

        if(!empty($materielContentData)) {
            $updateOperateData = [];
            $discountContentData = [];//扣除原料表中对应的原料信息
            foreach($materielContentData as $v1) {
                $getSlaveContentInfo = ProductSlaveContentModel::where([
                    'product_order_id' => $data['id'],
                    'type_id' => $v1['type_id'],
                ])
                    ->first();

                $discountContentData[] = [
                    'id' => $getSlaveContentInfo['id'],
                    'storage_operate_num' => $getSlaveContentInfo['storage_operate_num'] + $v1['num'],
                ];

                //查找到未全部入库的所有
                $slaveContentStorage = ProductSlaveContentStorageModel::where([
                    'type_id' => $v1['type_id'],
                    'product_order_id' => $data['id'],
                ])
                    ->whereRaw('num != storage_operate_num')
                    ->orderBy('storage_operate_num', 'asc')
                    ->get()->toArray();


                if(empty($slaveContentStorage)) {
                    throw new Exception('原料已无可入库内容，请重试');
                }

                $tempNum = $getSlaveContentInfo['storage_operate_num'] + $v1['num'];//实际消耗数量 11

                //递归扣除所需的库存数量
                foreach($slaveContentStorage as $val) {
                    $nowLeftNum = $val['num'] - $val['storage_operate_num'];//当前剩余可操作数量

                    if($tempNum <= $nowLeftNum || ($tempNum - $nowLeftNum == 0)) {
                        $updateOperateData[] = [
                            'id' => $val['id'],
                            'storage_operate_num' => $val['storage_operate_num'] + $tempNum
                        ];
                        break;
                    }
                    else {
                        $tempNum -= $nowLeftNum;//剩余可操作 5

                        if($tempNum > 0) {
                            $updateOperateData[] = [
                                'id' => $val['id'],
                                'storage_operate_num' => $val['storage_operate_num'] + $nowLeftNum
                            ];
                        }
                        else {
                            $updateOperateData[] = [
                                'id' => $val['id'],
                                'storage_operate_num' => $val['storage_operate_num'] + $tempNum
                            ];
                        }
                    }

                }
            }

            if(!empty($discountContentData)) {
                batch()->update(new ProductSlaveContentModel, $discountContentData, 'id');
            }

            if(!empty($updateOperateData)) {
                batch()->update(new ProductSlaveContentStorageModel, $updateOperateData, 'id');
            }
        }

        if(!empty($logData)) {
            LogInStorageModel::insert($logData);
        }

        if(!empty($slaveData)) {
            batch()->update(new ProductSlaveModel, $slaveData, 'id');
        }

        if(!empty($existStorageData)) {
            batch()->update(new StorageManageModel, $existStorageData, 'id');
        }

        if(!empty($productSerialData)) {
            batch()->update(new ProductSlaveContentStorageModel, $productSerialData, 'id');
        }

        if(!empty($storageSerialData)) {
            batch()->update(new SerialNumberModel, $storageSerialData, 'id');
        }

        return true;
    }

    private static function fullInStorage1(array $data, $productInfo)
    {
        $storageInfo = StorageModel::where([
            'id' => $data['storage_id'],
            'main_id' => $data['main_id'],
            'delete_flag' => 0
        ])->first();

        if(empty($storageInfo)) {
            return ['code' => 1, 'msg' => '仓库不存在', 'data' => ''];
        }

        if($data['use_shelf']) {
            if($data['location_id'] == 0) {
                throw new Exception('设置中已开启货架，请选择货架库位后重试');
            }

            $shelfId = $data['shelf_id'];
            $locationId = $data['location_id'];
        }
        else {
            $shelfInfo = StorageShelfModel::where('storage_id', $data['storage_id'])->where('shelf_type', 1)->first();
            $locationInfo = StorageShelfLocationModel::where([
                'shelf_id' => $shelfInfo['id'],
                'location_type' => 1
            ])->first();

            $shelfId = $shelfInfo['id'];
            $locationId = $locationInfo['id'];
        }

        if(empty($data['task_content'])) {
            throw new Exception('请选择要入库的生产任务');
        }

        $taskContent = json_decode($data['task_content'], true);

        $existStorageData = [];
        $serialData = [];//序列号信息
        $slaveData = [];//变更入库的生产任务数
        $logData = [];//日志信息
        $contentInfo = [];//生产原料信息
        foreach($taskContent as $value) {
            if($value['num'] == 0) {
                throw new Exception('入库数量不能为0');
            }

            $slaveInfo = ProductSlaveModel::where('id', $value['id'])->first();

            $slaveData[] = [
                'id' => $value['id'],
                'storage_operate_num' => $slaveInfo['storage_operate_num'] + $value['num'],
            ];

            if ($value['num'] > ($slaveInfo['num'] - $slaveInfo['storage_operate_num'])) {
                throw new Exception('超出可入库数量,当前可入库数量为' . ($slaveInfo['num'] - $slaveInfo['storage_operate_num']));
            }

            $materielTypeInfo = MaterielTypeModel::getMainInfo($value['type_id']);

            $checkStorageManageInfo = StorageManageModel::getInfos([
                'type_id' => $value['type_id'],
                'storage_id' => $data['storage_id'],
                'main_id' => $data['main_id'],
                'shelf_id' => $shelfId,
                'location_id' => $locationId
            ]);

            //商品是否开启序列号
//            if($materielTypeInfo['is_use_serial']) {
//                if(empty($value['serial_info'])) {
//                    throw new Exception('请填写序列号');
//                }
//
//                $serialInfo = explode(',', $value['serial_info']);
//
//                //验证本次入库填写的序列号数量是否与入库数量相符
//                if($value['num'] > count($serialInfo)) {
//                    throw new Exception('您所填写的序列号数量与要入库的商品数不符，请重新填写');
//                }
//            }

            $lastStorageNum = 0;
            $nextStorageNum = 0;
            if(empty($checkStorageManageInfo)) {
                $storageManageId = StorageManageModel::insertGetId([
                    'materiel_class_id' => $materielTypeInfo['materiel_class_id'],
                    'materiel_class_name' => $materielTypeInfo['sec_class_name'],
                    'materiel_class_no' => $materielTypeInfo['sec_class_no'],
                    'type_id' => $materielTypeInfo['id'],
                    'materiel_name' => $materielTypeInfo['materiel_name'],
                    'type_name' => $materielTypeInfo['type_name'],
                    'materiel_no' => $materielTypeInfo['materiel_no'],
                    'materiel_mean_cost' => $materielTypeInfo['cost'],
                    'storage_id' => $data['storage_id'],
                    'storage_name' => $storageInfo['storage_name'],
                    'storage_address' => $storageInfo['storage_address'],
                    'in_storage_num' => $value['num'],
                    'virtual_storage_num' => $value['num'],
                    'main_id' => $data['main_id'],
                    'in_storage_time' => time(),
                    'is_product_materiel' => $materielTypeInfo['is_product_materiel'],
                    'created_at' => time(),
                    'shelf_id' => $shelfId,
                    'location_id' => $locationId
                ]);

                $lastStorageNum = 0;
                $nextStorageNum = $value['num'];
            }
            else {
                $lastStorageNum = $checkStorageManageInfo['in_storage_num'];
                $nextStorageNum = $checkStorageManageInfo['in_storage_num'] + $value['num'];
                $storageManageId = $checkStorageManageInfo['id'];

                $existStorageData[] = [
                    'id' => $checkStorageManageInfo['id'],
                    'virtual_storage_num' => $checkStorageManageInfo['virtual_storage_num'] + $value['num'],
                    'in_storage_num' => $nextStorageNum,
                    'delete_flag' => 0
                ];
            }

            //商品是否为套餐
            if($materielTypeInfo['is_product_materiel']) {
                //获取所有套件内容
                $MaterielContentInfo = MaterielProductContentModel::where('product_id', $materielTypeInfo['id'])->get()->toArray();

                foreach($MaterielContentInfo as $MaterielContentValue) {
                    //生产任务入库所需的原料数量
                    $operateNum = $value['num'] * $MaterielContentValue['num'];

                    //生产原料信息
                    $slaveContent = ProductSlaveContentModel::where([
                        'type_id' => $MaterielContentValue['type_id'],
                        'product_order_id' => $data['id'],
                    ])
                        ->first();

                    if(!empty($contentInfo[$slaveContent['id']])) {
                        //增加生产原料已入库数量
                        $contentInfo[$slaveContent['id']] = [
                            'id' => $slaveContent['id'],
                            'type_id' => $value['type_id'],
                            'is_use_serial' => $materielTypeInfo['is_use_serial'],
                            'serial_info' => $value['serial_info'],
                            'is_product_materiel' => $materielTypeInfo['is_product_materiel'],
                            'storage_operate_num' => $contentInfo[$slaveContent['id']]['storage_operate_num'] + $operateNum
                        ];
                    }
                    else {
                        $contentInfo[$slaveContent['id']] = [
                            'id' => $slaveContent['id'],
                            'type_id' => $value['type_id'],
                            'is_product_materiel' => $materielTypeInfo['is_product_materiel'],
                            'is_use_serial' => $materielTypeInfo['is_use_serial'],
                            'serial_info' => $value['serial_info'],
                            'storage_operate_num' => $operateNum
                        ];
                    }
                }
            }
            else {
                //生产原料信息
                $materielTypeContent = ProductSlaveContentModel::where([
                    'type_id' => $value['type_id'],
                    'product_order_id' => $data['id'],
                ])
                    ->first();

                //生产任务入库所需的原料数量
                $operateNum = $value['num'];

                //生产原料信息
                $slaveContent = ProductSlaveContentModel::where([
                    'type_id' => $value['type_id'],
                    'product_order_id' => $data['id'],
                ])
                    ->first();

                if(!empty($contentInfo[$slaveContent['id']])) {
                    //增加生产原料已入库数量
                    $contentInfo[$slaveContent['id']] = [
                        'id' => $slaveContent['id'],
                        'type_id' => $value['type_id'],
                        'is_use_serial' => $materielTypeInfo['is_use_serial'],
                        'serial_info' => $value['serial_info'],
                        'is_product_materiel' => $materielTypeInfo['is_product_materiel'],
                        'storage_operate_num' => $contentInfo[$slaveContent['id']]['storage_operate_num'] + $operateNum
                    ];
                }
                else {
                    $contentInfo[$slaveContent['id']] = [
                        'id' => $slaveContent['id'],
                        'type_id' => $value['type_id'],
                        'is_use_serial' => $materielTypeInfo['is_use_serial'],
                        'serial_info' => $value['serial_info'],
                        'is_product_materiel' => $materielTypeInfo['is_product_materiel'],
                        'storage_operate_num' => $operateNum
                    ];
                }
            }

            $logData[] = [
                'type' => 0,
                'curr_storage_manage_id' => $storageManageId,
                'storage_id' => $data['storage_id'],
                'storage_name' => $storageInfo['storage_name'],
                'storage_address' => $storageInfo['storage_address'],
                'materiel_class_id' => $materielTypeInfo['materiel_class_id'],
                'materiel_class_name' => $materielTypeInfo['sec_class_name'],
                'materiel_class_no' => $materielTypeInfo['sec_class_no'],
                'materiel_type_id' => $materielTypeInfo['id'],
                'materiel_name' => $materielTypeInfo['materiel_name'],
                'type_name' => $materielTypeInfo['type_name'],
                'materiel_no' => $materielTypeInfo['materiel_no'],
                'purchase_no' => $productInfo['product_no'],
                'operate_num' => $value['num'],
                'last_storage_num' => $lastStorageNum,
                'next_storage_num' => $nextStorageNum,
                'materiel_mean_cost' => $materielTypeInfo['cost'],
                'serial_number' => $value['serial_info'],
                'all_id_type' => 4,
                'all_id' => $data['id'],
                'user_id' => $data['user_id'],
                'main_id' => $data['main_id'],
                'in_storage_time' => time(),
                'created_at' => time(),
                'shelf_id' => $shelfId,
                'remark' => empty($value['remark'])?'':$value['remark'],
                'location_id' => $locationId
            ];

            MessageService::sendInSms(
                '',
                $materielTypeInfo['materiel_name'],
                $materielTypeInfo['type_name'],
                $data['storage_id'],
                $storageInfo['storage_name'],
                $data['user_id'],
                $value['num'],
                $nextStorageNum,
            );
        }

        if(!empty($logData)) {
            LogInStorageModel::insert($logData);
        }

        if(!empty($existStorageData)) {
            batch()->update(new StorageManageModel, $existStorageData, 'id');
        }

        if(!empty($serialData)) {
            SerialNumberModel::insert($serialData);
        }

        if(!empty($slaveData)) {
            batch()->update(new ProductSlaveModel, $slaveData, 'id');
        }

        $newContentInfo = [];
        $updateSerialData = [];//更新原料库存序列号表信息
        $updateOperateData = [];//更新原料库存数量
        if(!empty($contentInfo)) {
            foreach($contentInfo as $contentVals) {
                if(!$contentVals['is_use_serial']) {
                    $checkProductContentInfo = ProductSlaveContentModel::where([
                        'id' => $contentVals['id']
                    ])->first();

                    $contentRestNum = $checkProductContentInfo['num'] - $checkProductContentInfo['storage_operate_num'];
                    if($contentRestNum < $contentVals['storage_operate_num']) {
                        throw new Exception('生产任务对应的可入库生产原料不足，请检查生产任务入库数量后重试');
                    }

                    $newContentInfo[] = [
                        'id' => $contentVals['id'],
                        'type_id' => $contentVals['type_id'],
                        'storage_operate_num' => $contentVals['storage_operate_num'] + $checkProductContentInfo['storage_operate_num'],
                    ];

                    //查找到未全部入库的所有
                    $slaveContentStorage = ProductSlaveContentStorageModel::where([
                        'type_id' => $contentVals['type_id'],
                        'product_order_id' => $data['id'],
                    ])
                        ->whereRaw('num != storage_operate_num')
                        ->orderBy('storage_operate_num', 'asc')
                        ->get()->toArray();

                    if(empty($slaveContentStorage)) {
                        throw new Exception('原料已无可入库内容，请重试');
                    }

                    $tempNum = $contentVals['storage_operate_num'];//实际消耗数量 11

                    //递归扣除所需的库存数量
                    foreach($slaveContentStorage as $val) {
                        $nowLeftNum = $val['num'] - $val['storage_operate_num'];//当前剩余可操作数量

                        if($tempNum <= $nowLeftNum || ($tempNum - $nowLeftNum == 0)) {
                            $updateOperateData[] = [
                                'id' => $val['id'],
                                'storage_operate_num' => $val['storage_operate_num'] + $tempNum
                            ];
                            break;
                        }
                        else {
                            $tempNum -= $nowLeftNum;//剩余可操作 5

                            if($tempNum > 0) {
                                $updateOperateData[] = [
                                    'id' => $val['id'],
                                    'storage_operate_num' => $val['storage_operate_num'] + $nowLeftNum
                                ];
                            }
                            else {
                                $updateOperateData[] = [
                                    'id' => $val['id'],
                                    'storage_operate_num' => $val['storage_operate_num'] + $tempNum
                                ];
                            }
                        }

                    }
                }
                else {
                    $getSerialData = array_filter(explode(',', $contentVals['serial_info']), function($v) { return $v !== ''; });

                    $contentStorageInfo = ProductSlaveContentStorageModel::where([
                        'main_id' => $data['main_id'],
                        'product_order_id' => $data['id'],
                    ])
                        ->whereIn('serial_id', $getSerialData)
                        ->get()
                        ->toArray();

                    foreach($contentStorageInfo as $serialData) {
                        if($serialData['num'] == $serialData['storage_operate_num']) {
                            throw new Exception('生产任务入库时生产原料存在已被使用的序列号，请重试');
                        }

                        $updateSerialData[] = [
                            'goods_id' => $serialData['type_id'],
                            'id' => $serialData['serial_id'],
                            'materiel_package_id' => $contentVals['type_id'],
                            'status' => 1
                        ];

                        ProductSlaveContentStorageModel::where([
                            'serial_id' => $serialData['id'],
                            'product_order_id' => $data['id'],
                        ])
                            ->increment('storage_operate_num', 1);
                    }
                }
            }

            if(!empty($newContentInfo)) {
                batch()->update(new ProductSlaveContentModel, $newContentInfo, 'id');
            }

            if(!empty($updateSerialData)) {
                batch()->update(new SerialNumberModel, $updateSerialData, 'id');
            }

            if(!empty($updateOperateData)) {
                batch()->update(new ProductSlaveContentStorageModel, $updateOperateData, 'id');
            }
        }

        ProductOrderModel::where('id', $data['id'])
            ->update([
                'in_storage_type' => 1
            ]);

        return true;
    }

    //套件返仓
    private static function piecesInStorage(array $data, $productInfo)
    {
        if(empty($data['materiel_content'])) {
            throw new Exception('请选择要入库的生产原料');
        }

        $materielContent = json_decode($data['materiel_content'], true);

        $serialData = [];//序列号重新入库
        $storageManageData = [];
        $logData = [];
        $slaveContentData = [];
        foreach($materielContent as $value) {
            if($value['num'] == 0) {
                throw new Exception('生产原料数量不能为0');
            }

            $productContentInfo = ProductSlaveContentModel::where([
                'product_order_id' => $data['id'],
                'type_id' => $value['type_id'],
            ])->first();

            $afterNum = $productContentInfo['storage_operate_num'] + $value['num'];//操作后数量
            if($value['num'] < $productContentInfo['num'] && $afterNum < $productContentInfo['num']) {
                throw new Exception('可入库数量不足，当前可入库数量为:'.($productContentInfo['num'] - $productContentInfo['storage_operate_num']));
            }

            $slaveContentData[] = [
                'id' => $productContentInfo['id'],
                'storage_operate_num' => $productContentInfo['storage_operate_num'] + $value['num'],
            ];

            $num = 0;
            if(!empty($value['serial_info']) && !empty($value['storage_manage_info'])) {
                if(!empty($value['serial_info'])) {
                    if($value['num'] != count($value['serial_info'])) {
                        throw new Exception('返仓所需的序列号与实际选取的序列号数量不符，请重试');
                    }

                    foreach($value['serial_info'] as $serialVal) {
                        $serialInfo = SerialNumberModel::where('id', $serialVal['serial_id'])->first();

                        if($serialInfo['status']) {
                            throw new Exception('序列号已存在，无法进行返仓');
                        }

                        $serialData[] = [
                            'id' => $serialVal['id'],
                            'status' => 1
                        ];

                        $num += $serialVal['num'];
                        $storageManageInfo = StorageManageModel::detail(['id' => $serialVal['storage_manage_id']]);

                        $storageManageData[] = [
                            'id' => $storageManageInfo['id'],
                            'virtual_storage_num' => $storageManageInfo['virtual_storage_num'] + $serialVal['num'],
                            'in_storage_num' => $storageManageInfo['in_storage_num'] + $serialVal['num'],
                            'delete_flag' => 0
                        ];

                        $logData[] = self::inStorageLog(
                            $data,
                            $serialVal['num'],
                            $storageManageInfo,
                            $serialInfo['serial_no'],
                            4,
                            $productInfo['product_no'],
                            $value['remark']
                        );
                    }
                }
                else {
                    foreach($value['storage_manage_info'] as $storageManageVal) {
                        $num += $storageManageVal['num'];

                        $storageManageData[] = [
                            'id' => $storageManageInfo['id'],
                            'virtual_storage_num' => $storageManageInfo['virtual_storage_num'] + $storageManageVal['num'],
                            'in_storage_num' => $storageManageInfo['in_storage_num'] + $storageManageVal['num'],
                            'delete_flag' => 0
                        ];

                        $logData[] = self::inStorageLog(
                            $data,
                            $storageManageVal['num'],
                            $storageManageInfo,
                            '',
                            4,
                            $productInfo['product_no'],
                            $value['remark']
                        );
                    }
                }
            }
            else {
                throw new Exception('请选择库存或序列号信息');
            }

            if($value['num'] > $num) {
                throw new Exception('序列号或库存信息中入库数量与商品实际需入库数量不匹配');
            }
        }

        if(!empty($serialData)) {
            batch()->update(new SerialNumberModel, $serialData, 'id');
        }

        if(!empty($storageManageData)) {
            batch()->update(new StorageManageModel, $storageManageData, 'id');
        }

        if(!empty($logData)) {
            LogInStorageModel::insert($logData);
        }

        if(!empty($slaveContentData)) {
            batch()->update(new ProductSlaveContentModel, $slaveContentData, 'id');
        }

        ProductOrderModel::where('id', $data['id'])
            ->update([
                'in_storage_type' => 2
            ]);

        return true;
    }

    public static function productOutStorage(array $data, $productInfo, $time)
    {
        if(empty($data['task_content'])) {
            throw new Exception('请选择要出库的生产任务');
        }

        $taskContent = json_decode($data['task_content'], true);

        $productStorageInfo = StorageModel::select(
            'a.id as storage_id',
            'a.storage_name',
            'a.storage_address',
            'b.id as shelf_id',
            'c.id as location_id'
        )
            ->from('storage as a')
            ->leftJoin('storage_shelf as b', 'b.storage_id', '=', 'a.id')
            ->leftJoin('storage_shelf_location as c', 'c.shelf_id', '=', 'b.id')
            ->where([
                'is_product_storage' => 1,
                'a.main_id' => $data['main_id']
            ])->first();

        $taskData = [];//生产任务可出库更新所需数据
        $logData = [];
        $contentSerialData = [];//生产订单需使用的序列号信息
        $typeContentData = [];
        $serialData = [];

        $sellInfo = [];
        foreach($taskContent as $value) {
            if ($value['num'] == 0) {
                throw new Exception('生产任务数量不能为0');
            }

            $slaveInfo = ProductSlaveModel::select(
                'a.num',
                'a.storage_operate_num',
                'b.materiel_name',
                'b.type_name',
                'b.materiel_no',
                'b.id as type_id',
                'c.id as s_class_id',
                'c.class_name as s_class_name',
                'c.class_no as s_class_no',
                'is_use_serial',
                'b.is_product_materiel'
            )
                ->from('product_slave as a')
                ->leftJoin('materiel_type as b', 'b.id', '=', 'a.type_id')
                ->leftJoin('materiel_class as c', 'c.id', '=', 'b.materiel_class_id')
                ->where([
                    'a.id' => $value['id'],
                  /*   'a.type_id' => $value['type_id'],
                    'product_order_id' => $data['id'] */
                ])->first()->toArray();

            if($slaveInfo['num'] < ($slaveInfo['storage_operate_num'] + $value['num'])) {
                throw new Exception('无法出库：出库数量超出剩余可出库数量');
            }

            //是否为套餐
            if($slaveInfo['is_product_materiel']) {
                $productContentData = MaterielProductContentModel::where('product_id', $value['type_id'])->get()->toArray();

                foreach($productContentData as $vv1) {
                    if(!$vv1['is_use_serial']) {
                        $typeContentData[] = [
                            'type_id' => $vv1['type_id'],
                            'storage_operate_num' => $value['num'] * $vv1['num']
                        ];
                    }
                }
            }
            else {
                $typeContentData[] = [
                    'type_id' => $value['type_id'],
                    'storage_operate_num' => $value['num']
                ];
            }

            $sellGoodsDetail = SellGoodsDetail::where([
                'materiel_type_id' => $value['type_id'],
                'sell_id' => $productInfo['product_source_id'],
            ])->first();

            if($slaveInfo['is_use_serial'] && empty($value['serial_info'])) {
                throw new Exception('商品已开启序列号，请选择序列号后重试');
            }
            else if($slaveInfo['is_use_serial'] && !empty($value['serial_info'])){
                $serialInfo = array_filter(explode(',', $value['serial_info']));

                foreach($serialInfo as $serialIdVal) {
                    $serialModel = SerialNumberModel::where('main_id', $data['main_id'])
                        ->where('id', $serialIdVal)->first();

                    $contentSerialData[] = [
                        'product_order_id' => $data['id'],
                        'serial_id' => $serialIdVal,
                    ];
                    $sInfo = "";
                    if(!empty($value['type_id']) && !empty($sellGoodsDetail)){
                        if(empty($sellGoodsDetail['location_id']) || $sellGoodsDetail['shelf_id']){
                            $shelfInfo = StorageShelfModel::where([
                                'shelf_type' => 1,
                                'storage_id' => $sellGoodsDetail['warehouse_id']
                            ])->first();
                            $shelfLocationInfo = StorageShelfLocationModel::where([
                                'location_type' => 1,
                                'storage_id' => $sellGoodsDetail['warehouse_id']
                            ])->first();
                        }
                        $sInfo = StorageManageModel::select('id')->where([
                            'type_id'     => $value['type_id'],
                            'storage_id'  => $sellGoodsDetail['warehouse_id'],
                            'location_id' => !empty($sellGoodsDetail['location_id'])?$sellGoodsDetail['location_id']:$shelfLocationInfo['id'],
                            'shelf_id'    => !empty($sellGoodsDetail['shelf_id'])?$sellGoodsDetail['shelf_id']:$shelfInfo['id']
                        ])->where(['delete_flag'=>0])->first();
                    }
                    if(!empty($sInfo) && empty($slaveInfo['is_product_materiel'])){
                        $serialData[] = [
                            'id' => $serialIdVal,
                            'package_id' => $slaveInfo['is_product_materiel']?$value['type_id']:0,
                            'storage_manage_id'=>$sInfo['id'],
                            'goods_id'=>$value['type_id'],
                        ];
                    }else{
                        $serialData[] = [
                            'id' => $serialIdVal,
                            'package_id' => $slaveInfo['is_product_materiel']?$value['type_id']:0,
                        ];
                    }
                }
            }

            if($slaveInfo['is_use_serial'] && empty($value['serial_info'])) {
                throw new Exception('商品已开启序列号，请选择序列号后重试');
            }

            //更新任务可操作数量
            $taskData[] = [
                'id' => $value['id'],
                'storage_operate_num' => $slaveInfo['storage_operate_num'] + $value['num'],
            ];



            $sellInfo[] = [
                'id' => $sellGoodsDetail['id'],
                'out_num' => $sellGoodsDetail['out_num'] + $value['num'],
            ];

            $serialStr = '';
            if(!empty($value['serial_info'])) {
                $serialIdArr = array_filter(explode(',', $value['serial_info']));

                $serialInfos = SerialNumberModel::whereIn('id', $serialIdArr)->get()->toArray();

                foreach($serialInfos as $serialInfosVal) {
                    $serialStr .= $serialInfosVal['serial_no'].',';
                }

                $serialStr = substr($serialStr, 0, -1);
            }

            $logData[] = [
                'type' => 0,
                'storage_id' => $productStorageInfo['storage_id'],
                'storage_name' => $productStorageInfo['storage_name'],
                'storage_address' => $productStorageInfo['storage_address'],
                'curr_storage_manage_id' => 0,
                'materiel_class_id' => $slaveInfo['s_class_id'],
                'materiel_class_name' => $slaveInfo['s_class_name'],
                'materiel_class_no' => $slaveInfo['s_class_no'],
                'materiel_type_id' => $slaveInfo['type_id'],
                'materiel_name' => $slaveInfo['materiel_name'],
                'type_name' => $slaveInfo['type_name'],
                'materiel_no' => $slaveInfo['materiel_no'],
                'relation_code' => '',
                'operate_num' => $value['num'],
                'serial_number' => $serialStr,
                'last_storage_num' => $slaveInfo['storage_operate_num'],
                'next_storage_num' => $slaveInfo['storage_operate_num'] - $value['num'],
                'materiel_mean_cost' => '',
                'fact_out_time' => strtotime(date('Y-m-d')),
                'all_id_type' => 3,
                'all_id' => $data['id'],
                'user_id' => $data['user_id'],
                'main_id' => $data['main_id'],
                'out_storage_time' => $data['in_storage_time'],
                'created_at' => $time,
                'remark' => empty($remark)?'':$remark,
                'shelf_id' => $productStorageInfo['shelf_id'],
                'location_id' => $productStorageInfo['location_id'],
            ];
        }

        if(!empty($logData)) {
            LogOutStorageModel::insert($logData);
        }

        if(!empty($sellInfo)) {
            batch()->update(new SellGoodsDetail, $sellInfo, 'id');
        }

        if(!empty($taskData)) {
            batch()->update(new ProductSlaveModel, $taskData, 'id');
        }

        if(!empty($serialData)) {
            batch()->update(new SerialNumberModel, $serialData, 'id');
        }

        //出库时增加库存中已使用的商品数量
        if(!empty($contentSerialData)) {
            $serialIdInfo = [];
            foreach($contentSerialData as $vv2) {
                $serialIdInfo[] = $vv2['serial_id'];
                ProductSlaveContentStorageModel::where($vv2)->increment('storage_operate_num', 1, [
                    'is_out' => 1
                ]);
            }

//            batch()->update(new SerialNumberModel, $serialIdInfo, 'id');
        }
//        var_dump(123);die;
//        if(!empty($typeContentData)) {
//            foreach($typeContentData as $vv3) {
//                ProductSlaveContentStorageModel::where([
//                    'type_id' => $vv3['type_id'],
//                    'product_order_id' => $data['id']
//                ])
//                    ->increment('storage_operate_num', $vv3['storage_operate_num']);
//            }
//        }

        ProductOrderModel::where('id', $data['id'])
            ->update([
                'in_storage_type' => 3
            ]);

        return true;
    }

    //废弃
    private static function productOutStorageOld(array $data, $productInfo)
    {
        if(empty($data['materiel_content'])) {
            throw new Exception('请选择要出库的生产原料');
        }

        $materielContent = json_decode($data['materiel_content'], true);

        $serialData = [];
        $logData = [];
        $storageManageData = [];
        $slaveData = [];//变更出库的生产任务数
        foreach($materielContent as $value) {
            if ($value['num'] == 0) {
                throw new Exception('生产原料数量不能为0');
            }

            $slaveInfo = ProductSlaveModel::where('id', $value['id'])->first();

            $slaveData[] = [
                'id' => $value['id'],
                'storage_operate_num' => $slaveInfo['storage_operate_num'] + $value['num'],
            ];

            if ($value['num'] > ($slaveInfo['num'] - $slaveInfo['storage_operate_num'])) {
                throw new Exception('超出可入库数量,当前可入库数量为' . ($slaveInfo['num'] - $slaveInfo['storage_operate_num']));
            }

            $num = 0;
            if(!empty($value['serial_info']) && !empty($value['storage_manage_info'])) {
                if(!empty($value['serial_info'])) {
                    foreach($value['serial_info'] as $serialVal) {
                        $serialInfo = SerialNumberModel::where([
                            'id' => $serialVal['id'],
                            'main_id' => $data['main_id']
                        ])->first();

                        if(empty($serialInfo)) {
                            throw new Exception('序列号不存在，无法使用');
                        }

                        if($serialInfo['status'] == 0) {
                            throw new Exception('序列号:'.$serialInfo['num'].'已被使用，无法出库');
                        }

                        $num += $serialVal['num'];

                        $storageManageInfo = StorageManageModel::detail(['id' => $serialVal['storage_manage_id']]);

                        if(empty($storageManageInfo)) {
                            throw new Exception('无效库存，请重新选择');
                        }

                        if($storageManageInfo['virtual_storage_num'] < $serialVal['num']) {
                            throw new Exception('库存商品'.$storageManageInfo['materiel_name'].'-'.$storageManageInfo['type_name'].'可用库存数不足');
                        }

                        $storageManageData[] = [
                            'id' => $storageManageInfo['id'],
                            'virtual_storage_num' => $storageManageInfo['virtual_storage_num'] - $serialVal['num'],
                            'in_storage_num' => $storageManageInfo['in_storage_num'] - $serialVal['num'],
                        ];

                        $serialData[] = [
                            'id' => $serialInfo['id'],
                            'status' => 0
                        ];

                        $logData[] = self::outStorageLog($data, $serialVal['num'], $storageManageInfo, $serialInfo['serial_no'], 3, $productInfo['product_no'], $value['remark']);
                    }
                }
                else {
                    foreach($value['storage_manage_info'] as $storageManageVal) {
                        $storageManageInfo = StorageManageModel::detail(['id' => $storageManageVal['storage_manage_id']]);

                        if(empty($storageManageInfo)) {
                            throw new Exception('无效库存，请重新选择');
                        }

                        if($storageManageInfo['virtual_storage_num'] < $storageManageVal['num']) {
                            throw new Exception('库存商品'.$storageManageInfo['materiel_name'].'-'.$storageManageInfo['type_name'].'可用库存数不足');
                        }

                        $num += $storageManageVal['num'];

                        $storageManageData[] = [
                            'id' => $storageManageInfo['id'],
                            'virtual_storage_num' => $storageManageInfo['virtual_storage_num'] - $storageManageVal['num'],
                            'in_storage_num' => $storageManageInfo['in_storage_num'] - $storageManageVal['num'],
                        ];

                        $logData[] = self::outStorageLog($data, $serialVal['num'], $storageManageInfo, '', 3, $productInfo['product_no'], $value['remark']);
                    }
                }
            }
            else {
                throw new Exception('请选择要出库的库存信息');
            }

            if($value['num'] > $num) {
                throw new Exception('序列号或库存信息中入库数量与商品实际需入库数量不匹配');
            }
        }

        if(!empty($serialData)) {
            batch()->update(new SerialNumberModel, $serialData, 'id');
        }

        if(!empty($storageManageData)) {
            batch()->update(new StorageManageModel, $storageManageData, 'id');
        }

        if(!empty($logData)) {
            LogOutStorageModel::insert($logData);
        }

        if(!empty($slaveData)) {
            batch()->update(new ProductSlaveModel, $slaveData, 'id');
        }

        ProductOrderModel::where('id', $data['id'])
            ->update([
                'in_storage_type' => 2
            ]);

        return true;
    }

    public static function productSerialSelect($data, $keyword) {
        //获取所有套件内容
        $contentInfo = MaterielProductContentModel::where('product_id', $data['type_id'])
            ->get()->toArray();

        $contentTypeId = [];
        foreach($contentInfo as $contentVal) {
            $contentTypeId[] = $contentVal['type_id'];
        }

        $slaveContentStorageInfo = ProductSlaveContentStorageModel::where([
            'product_order_id' => $data['id'],
            'flag' => 0
        ])
            ->whereIn('type_id', $contentTypeId)
            ->get()->toArray();

        $contentStorageSerialId = [];
        foreach($slaveContentStorageInfo as $contentStorageSerialVal) {
            $contentStorageSerialId[] = $contentStorageSerialVal['serial_id'];
        }

        $fillInfo = ProductFillOrBalanceContentModel::where([
            'type' => 0,
            'product_order_id' => $data['id'],
        ])
            ->whereIn('type_id', $contentTypeId)
            ->get()->toArray();


        if(!empty($fillInfo)) {
            foreach($fillInfo as $fillSerialVal) {
                $contentStorageSerialId[] = $fillSerialVal['serial_id'];
            }
        }

        $balanceInfo = ProductFillOrBalanceContentModel::where([
            'type' => 1,
            'product_order_id' => $data['id'],
        ])
            ->whereIn('type_id', $contentTypeId)
            ->get()->toArray();

        if(!empty($balanceInfo)) {
            foreach($balanceInfo as $balanceValue) {
                if(in_array($balanceValue['serial_id'], $contentStorageSerialId)) {
                    $key = array_search($balanceValue['serial_id'], $contentStorageSerialId);
                    unset($contentStorageSerialId[$key]);
                }
            }
        }

        $newData = SerialNumberModel::select(
            'a.id as serial_id',
            'b.type_id',
            'c.materiel_name',
            'c.type_name',
            'a.storage_manage_id',
            'a.serial_no'
        )
            ->from('serial_number as a')
            ->leftJoin('storage_manage as b', 'b.id', '=', 'a.storage_manage_id')
            ->leftJoin('materiel_type as c', 'c.id', '=', 'b.type_id')
            ->whereIn('a.id', $contentStorageSerialId)
            ->get()->toArray();

        $result = [];
        foreach($newData as &$value) {
            $materielProductContentInfo = MaterielProductContentModel::where([
                'type_id' => $value['type_id'],
                'product_id' => $data['type_id']
            ])->first();

            $result[$value['type_id']]['type_id'] = $value['type_id'];
            $result[$value['type_id']]['materiel_name'] = $value['materiel_name'];
            $result[$value['type_id']]['type_name'] = $value['type_name'];
            $result[$value['type_id']]['num'] = $materielProductContentInfo['num'];
            $result[$value['type_id']]['serial_info'][] = [
                'serial_id' => $value['serial_id'],
                'serial_no' => $value['serial_no'],
                'storage_manage_id' => $value['storage_manage_id']
            ];
        }

        return array_values($result);
    }

    public static function productSerialSelect1($data, $keyword)
    {
        //获取所有套件内容
        $contentInfo = MaterielProductContentModel::where('product_id', $data['type_id'])
            ->get()->toArray();

        $productContentTypeId = [];//套件商品id
        foreach($contentInfo as $value) {
            $productContentTypeId[] = $value['type_id'];
        }

        $slaveContentStorageInfo = ProductSlaveContentStorageModel::select(
            'a.serial_id',
            'a.type_id',
            'materiel_name',
            'type_name',
            'serial_no',
            'a.storage_manage_id'
        )
            ->where([
                'product_order_id' => $data['id'],
            ])
                ->from('product_slave_content_storage as a')
                ->leftJoin('serial_number as b', 'b.id', '=', 'a.serial_id')
                ->leftJoin('materiel_type as c', 'c.id', '=', 'a.type_id')
                ->where('a.serial_id', '!=', 0)
                ->whereRaw('num > storage_operate_num')
                ->where(function($query) use ($keyword) {
                    $query->where('serial_no', 'like', '%'.$keyword.'%');
                })
                ->whereIn('a.type_id', $productContentTypeId)
            ->where('flag', 0)
                ->get()->toArray();

        $arr = [];
        foreach($slaveContentStorageInfo as $val) {
            $arr[$val['type_id']]['type_id'] = $val['type_id'];
            $arr[$val['type_id']]['materiel_name'] =$val['materiel_name'];
            $arr[$val['type_id']]['type_name'] =$val['type_name'];

            $fillInfo = ProductFillOrBalanceContentModel::where([
                'product_order_id' => $data['id'],
                'type' => 1,
            ])
                ->where('serial_id', $val['serial_id'])->first();

            if(empty($fillInfo)) {
                $arr[$val['type_id']]['serial_info'][] = [
                    'serial_id' => $val['serial_id'],
                    'serial_no' => $val['serial_no'],
                    'storage_manage_id' => $val['storage_manage_id']
                ];
            }
            else {
                $arr[$val['type_id']]['serial_info'] = [];
            }
        }

        return array_values($arr);
    }
}
